diff --git a/.config/nextest.toml b/.config/nextest.toml index 1e18f8b5589c..912bf2514a77 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -124,3 +124,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/zepter.yaml b/.config/zepter.yaml index 7a67ba2695cf..24441e90b1a0 100644 --- a/.config/zepter.yaml +++ b/.config/zepter.yaml @@ -27,7 +27,7 @@ workflows: ] # The umbrella crate uses more features, so we to check those too: check_umbrella: - - [ $check.0, '--features=serde,experimental,riscv,runtime,with-tracing,tuples-96,with-tracing', '-p=polkadot-sdk' ] + - [ $check.0, '--features=serde,experimental,runtime,with-tracing,tuples-96,with-tracing', '-p=polkadot-sdk' ] # Same as `check_*`, but with the `--fix` flag. default: - [ $check.0, '--fix' ] diff --git a/.github/actions/set-up-gh/action.yml b/.github/actions/set-up-gh/action.yml index fc16ce0b2633..4dc3af4a19f2 100644 --- a/.github/actions/set-up-gh/action.yml +++ b/.github/actions/set-up-gh/action.yml @@ -1,5 +1,5 @@ -name: 'install gh' -description: 'Install the gh cli in a debian based distro and switches to the PR branch.' +name: "install gh" +description: "Install the gh cli in a debian based distro and switches to the PR branch." inputs: pr-number: description: "Number of the PR" @@ -9,28 +9,20 @@ inputs: required: true outputs: branch: - description: 'Branch name for the PR' + description: "Branch name for the PR" value: ${{ steps.branch.outputs.branch }} runs: using: "composite" steps: - - name: Instal gh cli - shell: bash - # Here it would get the script from previous step - run: | - (type -p wget >/dev/null || (apt update && apt-get install wget -y)) - mkdir -p -m 755 /etc/apt/keyrings - wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null - chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null - apt update - apt install gh -y - git config --global --add safe.directory '*' - - run: gh pr checkout ${{ inputs.pr-number }} - shell: bash - env: - GITHUB_TOKEN: ${{ inputs.GH_TOKEN }} - - name: Export branch name - shell: bash - run: echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT" - id: branch + - name: Set up git + shell: bash + # Here it would get the script from previous step + run: git config --global --add safe.directory '*' + - run: gh pr checkout ${{ inputs.pr-number }} + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.GH_TOKEN }} + - name: Export branch name + shell: bash + run: echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT" + id: branch 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/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 b5835f1f3085..9da05cac17b9 100755 --- a/.github/scripts/cmd/cmd.py +++ b/.github/scripts/cmd/cmd.py @@ -6,6 +6,7 @@ import argparse import _help import importlib.util +import re _HelpAction = _help._HelpAction @@ -15,12 +16,21 @@ runtimeNames = list(map(lambda x: x['name'], runtimesMatrix)) common_args = { - '--continue-on-fail': {"action": "store_true", "help": "Won't exit(1) on failed command and continue with next steps. "}, '--quiet': {"action": "store_true", "help": "Won't print start/end/failed messages in PR"}, '--clean': {"action": "store_true", "help": "Clean up the previous bot's & author's comments in PR"}, '--image': {"help": "Override docker image '--image docker.io/paritytech/ci-unified:latest'"}, } +def print_and_log(message, output_file='/tmp/cmd/command_output.log'): + print(message) + with open(output_file, 'a') as f: + f.write(message + '\n') + +def setup_logging(): + if not os.path.exists('/tmp/cmd'): + os.makedirs('/tmp/cmd') + open('/tmp/cmd/command_output.log', 'w') + parser = argparse.ArgumentParser(prog="/cmd ", description='A command runner for polkadot-sdk repo', add_help=False) parser.add_argument('--help', action=_HelpAction, help='help for help if you need some help') # help for help for arg, config in common_args.items(): @@ -28,21 +38,23 @@ subparsers = parser.add_subparsers(help='a command to run', dest='command') +setup_logging() + """ -BENCH +BENCH """ bench_example = '''**Examples**: - Runs all benchmarks + 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 continues even if some benchmarks fail - %(prog)s --runtime westend --continue-on-fail - - Does not output anything and cleans up the previous bot's & author command triggering comments in PR + + 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 ''' @@ -53,16 +65,17 @@ parser_bench.add_argument('--runtime', help='Runtime(s) space separated', choices=runtimeNames, nargs='*', default=runtimeNames) 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') """ -FMT +FMT """ parser_fmt = subparsers.add_parser('fmt', help='Formats code (cargo +nightly-VERSION fmt) and configs (taplo format)') for arg, config in common_args.items(): parser_fmt.add_argument(arg, **config) """ -Update UI +Update UI """ parser_ui = subparsers.add_parser('update-ui', help='Updates UI tests') for arg, config in common_args.items(): @@ -77,7 +90,7 @@ spec.loader.exec_module(generate_prdoc) parser_prdoc = subparsers.add_parser('prdoc', help='Generates PR documentation') -generate_prdoc.setup_parser(parser_prdoc) +generate_prdoc.setup_parser(parser_prdoc, pr_required=False) def main(): global args, unknown, runtimesMatrix @@ -104,7 +117,7 @@ def main(): 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}").read() + 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() raw_pallets = output.strip().split('\n') all_pallets = set() @@ -156,12 +169,22 @@ def main(): manifest_path = os.popen(search_manifest_path).read() if not manifest_path: print(f'-- pallet {pallet} not found in dev runtime') - exit(1) + 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") + # TODO: we can remove once all pallets in dev runtime are migrated to polkadot-sdk-frame + try: + uses_polkadot_sdk_frame = "true" in os.popen(f"cargo metadata --locked --format-version 1 --no-deps | jq -r '.packages[] | select(.name == \"{pallet.replace('_', '-')}\") | .dependencies | any(.name == \"polkadot-sdk-frame\")'").read() + # Empty output from the previous os.popen command + except StopIteration: + uses_polkadot_sdk_frame = False template = config['template'] + if uses_polkadot_sdk_frame and re.match(r"frame-(:?umbrella-)?weight-template\.hbs", os.path.normpath(template).split(os.path.sep)[-1]): + template = "substrate/.maintain/frame-umbrella-weight-template.hbs" else: default_path = f"./{config['path']}/src/weights" xcm_path = f"./{config['path']}/src/weights/xcm" @@ -182,11 +205,13 @@ def main(): f"--repeat=20 " \ f"--heap-pages=4096 " \ f"{f'--template={template} ' if template else ''}" \ - f"--no-storage-info --no-min-squares --no-median-slopes" + f"--no-storage-info --no-min-squares --no-median-slopes " \ + f"{config['bench_flags']}" print(f'-- Running: {cmd} \n') status = os.system(cmd) - if status != 0 and not args.continue_on_fail: - print(f'Failed to benchmark {pallet} in {runtime}') + + 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 @@ -197,14 +222,14 @@ def main(): successful_benchmarks[f'{runtime}'] = successful_benchmarks.get(f'{runtime}', []) + [pallet] if failed_benchmarks: - print('❌ Failed benchmarks of runtimes/pallets:') + print_and_log('❌ Failed benchmarks of runtimes/pallets:') for runtime, pallets in failed_benchmarks.items(): - print(f'-- {runtime}: {pallets}') + print_and_log(f'-- {runtime}: {pallets}') if successful_benchmarks: - print('✅ Successful benchmarks of runtimes/pallets:') + print_and_log('✅ Successful benchmarks of runtimes/pallets:') for runtime, pallets in successful_benchmarks.items(): - print(f'-- {runtime}: {pallets}') + print_and_log(f'-- {runtime}: {pallets}') elif args.command == 'fmt': command = f"cargo +nightly fmt" @@ -212,8 +237,8 @@ def main(): nightly_status = os.system(f'{command}') taplo_status = os.system('taplo format --config .config/taplo.toml') - if (nightly_status != 0 or taplo_status != 0) and not args.continue_on_fail: - print('❌ Failed to format code') + if (nightly_status != 0 or taplo_status != 0): + print_and_log('❌ Failed to format code') sys.exit(1) elif args.command == 'update-ui': @@ -221,18 +246,18 @@ def main(): print(f'Updating ui with `{command}`') status = os.system(f'{command}') - if status != 0 and not args.continue_on_fail: - print('❌ Failed to format code') + if status != 0: + print_and_log('❌ Failed to update ui') sys.exit(1) elif args.command == 'prdoc': # Call the main function from ./github/scripts/generate-prdoc.py module exit_code = generate_prdoc.main(args) - if exit_code != 0 and not args.continue_on_fail: - print('❌ Failed to generate prdoc') + if exit_code != 0: + print_and_log('❌ Failed to generate prdoc') sys.exit(exit_code) print('🚀 Done') if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/.github/scripts/cmd/test_cmd.py b/.github/scripts/cmd/test_cmd.py index f4e70903347f..7b29fbfe90d8 100644 --- a/.github/scripts/cmd/test_cmd.py +++ b/.github/scripts/cmd/test_cmd.py @@ -7,13 +7,45 @@ # Mock data for runtimes-matrix.json mock_runtimes_matrix = [ - {"name": "dev", "package": "kitchensink-runtime", "path": "substrate/frame", "header": "substrate/HEADER-APACHE2", "template": "substrate/.maintain/frame-weight-template.hbs", "bench_features": "runtime-benchmarks,riscv"}, - {"name": "westend", "package": "westend-runtime", "path": "polkadot/runtime/westend", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "bench_features": "runtime-benchmarks"}, - {"name": "rococo", "package": "rococo-runtime", "path": "polkadot/runtime/rococo", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "bench_features": "runtime-benchmarks"}, - {"name": "asset-hub-westend", "package": "asset-hub-westend-runtime", "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", "header": "cumulus/file_header.txt", "template": "cumulus/templates/xcm-bench-template.hbs", "bench_features": "runtime-benchmarks"}, + { + "name": "dev", + "package": "kitchensink-runtime", + "path": "substrate/frame", + "header": "substrate/HEADER-APACHE2", + "template": "substrate/.maintain/frame-weight-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--flag1 --flag2" + }, + { + "name": "westend", + "package": "westend-runtime", + "path": "polkadot/runtime/westend", + "header": "polkadot/file_header.txt", + "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--flag3 --flag4" + }, + { + "name": "rococo", + "package": "rococo-runtime", + "path": "polkadot/runtime/rococo", + "header": "polkadot/file_header.txt", + "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "" + }, + { + "name": "asset-hub-westend", + "package": "asset-hub-westend-runtime", + "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--flag7 --flag8" + } ] -def get_mock_bench_output(runtime, pallets, output_path, header, template = None): +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"--pallet={pallets} --header={header} " \ @@ -21,7 +53,8 @@ def get_mock_bench_output(runtime, pallets, output_path, header, template = None f"--wasm-execution=compiled " \ f"--steps=50 --repeat=20 --heap-pages=4096 " \ f"{f'--template={template} ' if template else ''}" \ - f"--no-storage-info --no-min-squares --no-median-slopes" + f"--no-storage-info --no-min-squares --no-median-slopes " \ + f"{bench_flags}" class TestCmd(unittest.TestCase): @@ -34,7 +67,7 @@ def setUp(self): self.patcher6 = patch('importlib.util.spec_from_file_location', return_value=MagicMock()) self.patcher7 = patch('importlib.util.module_from_spec', return_value=MagicMock()) self.patcher8 = patch('cmd.generate_prdoc.main', return_value=0) - + self.mock_open = self.patcher1.start() self.mock_json_load = self.patcher2.start() self.mock_parse_args = self.patcher3.start() @@ -63,12 +96,12 @@ def test_bench_command_normal_execution_all_runtimes(self): command='bench', runtime=list(map(lambda x: x['name'], mock_runtimes_matrix)), pallet=['pallet_balances'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None ), []) - + self.mock_popen.return_value.read.side_effect = [ "pallet_balances\npallet_staking\npallet_something\n", # Output for dev runtime "pallet_balances\npallet_staking\npallet_something\n", # Output for westend runtime @@ -76,7 +109,7 @@ def test_bench_command_normal_execution_all_runtimes(self): "pallet_balances\npallet_staking\npallet_something\n", # Output for asset-hub-westend runtime "./substrate/frame/balances/Cargo.toml\n", # Mock manifest path for dev -> pallet_balances ] - + with patch('sys.exit') as mock_exit: import cmd cmd.main() @@ -84,15 +117,34 @@ 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,riscv"), + 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(get_mock_bench_output('kitchensink', 'pallet_balances', './substrate/frame/balances/src/weights.rs', os.path.abspath('substrate/HEADER-APACHE2'), "substrate/.maintain/frame-weight-template.hbs")), - call(get_mock_bench_output('westend', 'pallet_balances', './polkadot/runtime/westend/src/weights', os.path.abspath('polkadot/file_header.txt'))), + + call(get_mock_bench_output( + runtime='kitchensink', + pallets='pallet_balances', + output_path='./substrate/frame/balances/src/weights.rs', + header=os.path.abspath('substrate/HEADER-APACHE2'), + bench_flags='--flag1 --flag2', + template="substrate/.maintain/frame-weight-template.hbs" + )), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_balances', + output_path='./polkadot/runtime/westend/src/weights', + header=os.path.abspath('polkadot/file_header.txt'), + bench_flags='--flag3 --flag4' + )), # skips rococo benchmark - call(get_mock_bench_output('asset-hub-westend', 'pallet_balances', './cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', os.path.abspath('cumulus/file_header.txt'))), + call(get_mock_bench_output( + runtime='asset-hub-westend', + pallets='pallet_balances', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', + header=os.path.abspath('cumulus/file_header.txt'), + bench_flags='--flag7 --flag8' + )), ] self.mock_system.assert_has_calls(expected_calls, any_order=True) @@ -101,7 +153,7 @@ def test_bench_command_normal_execution(self): command='bench', runtime=['westend'], pallet=['pallet_balances', 'pallet_staking'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None @@ -110,7 +162,7 @@ def test_bench_command_normal_execution(self): self.mock_popen.return_value.read.side_effect = [ "pallet_balances\npallet_staking\npallet_something\n", # Output for westend runtime ] - + with patch('sys.exit') as mock_exit: import cmd cmd.main() @@ -119,10 +171,22 @@ def test_bench_command_normal_execution(self): expected_calls = [ # Build calls call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), - + # Westend runtime calls - call(get_mock_bench_output('westend', 'pallet_balances', './polkadot/runtime/westend/src/weights', header_path)), - call(get_mock_bench_output('westend', 'pallet_staking', './polkadot/runtime/westend/src/weights', header_path)), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_balances', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_staking', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), ] self.mock_system.assert_has_calls(expected_calls, any_order=True) @@ -132,7 +196,7 @@ def test_bench_command_normal_execution_xcm(self): command='bench', runtime=['westend'], pallet=['pallet_xcm_benchmarks::generic'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None @@ -141,7 +205,7 @@ def test_bench_command_normal_execution_xcm(self): self.mock_popen.return_value.read.side_effect = [ "pallet_balances\npallet_staking\npallet_something\npallet_xcm_benchmarks::generic\n", # Output for westend runtime ] - + with patch('sys.exit') as mock_exit: import cmd cmd.main() @@ -150,14 +214,15 @@ def test_bench_command_normal_execution_xcm(self): expected_calls = [ # Build calls call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), - + # Westend runtime calls call(get_mock_bench_output( - 'westend', - 'pallet_xcm_benchmarks::generic', - './polkadot/runtime/westend/src/weights/xcm', - header_path, - "polkadot/xcm/pallet-xcm-benchmarks/template.hbs" + runtime='westend', + pallets='pallet_xcm_benchmarks::generic', + output_path='./polkadot/runtime/westend/src/weights/xcm', + header=header_path, + bench_flags='--flag3 --flag4', + template="polkadot/xcm/pallet-xcm-benchmarks/template.hbs" )), ] self.mock_system.assert_has_calls(expected_calls, any_order=True) @@ -167,7 +232,7 @@ def test_bench_command_two_runtimes_two_pallets(self): command='bench', runtime=['westend', 'rococo'], pallet=['pallet_balances', 'pallet_staking'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None @@ -176,7 +241,7 @@ def test_bench_command_two_runtimes_two_pallets(self): "pallet_staking\npallet_balances\n", # Output for westend runtime "pallet_staking\npallet_balances\n", # Output for rococo runtime ] - + with patch('sys.exit') as mock_exit: import cmd cmd.main() @@ -188,11 +253,35 @@ def test_bench_command_two_runtimes_two_pallets(self): call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), call("forklift cargo build -p rococo-runtime --profile release --features=runtime-benchmarks"), # Westend runtime calls - call(get_mock_bench_output('westend', 'pallet_staking', './polkadot/runtime/westend/src/weights', header_path)), - call(get_mock_bench_output('westend', 'pallet_balances', './polkadot/runtime/westend/src/weights', header_path)), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_staking', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_balances', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), # Rococo runtime calls - call(get_mock_bench_output('rococo', 'pallet_staking', './polkadot/runtime/rococo/src/weights', header_path)), - call(get_mock_bench_output('rococo', 'pallet_balances', './polkadot/runtime/rococo/src/weights', header_path)), + call(get_mock_bench_output( + runtime='rococo', + pallets='pallet_staking', + output_path='./polkadot/runtime/rococo/src/weights', + header=header_path, + bench_flags='' + )), + call(get_mock_bench_output( + runtime='rococo', + pallets='pallet_balances', + output_path='./polkadot/runtime/rococo/src/weights', + header=header_path, + bench_flags='' + )), ] self.mock_system.assert_has_calls(expected_calls, any_order=True) @@ -201,7 +290,7 @@ def test_bench_command_one_dev_runtime(self): command='bench', runtime=['dev'], pallet=['pallet_balances'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None @@ -220,14 +309,15 @@ def test_bench_command_one_dev_runtime(self): expected_calls = [ # Build calls - call("forklift cargo build -p kitchensink-runtime --profile release --features=runtime-benchmarks,riscv"), + call("forklift cargo build -p kitchensink-runtime --profile release --features=runtime-benchmarks"), # Westend runtime calls call(get_mock_bench_output( - 'kitchensink', - 'pallet_balances', - manifest_dir + "/src/weights.rs", - header_path, - "substrate/.maintain/frame-weight-template.hbs" + runtime='kitchensink', + pallets='pallet_balances', + output_path=manifest_dir + "/src/weights.rs", + header=header_path, + bench_flags='--flag1 --flag2', + template="substrate/.maintain/frame-weight-template.hbs" )), ] self.mock_system.assert_has_calls(expected_calls, any_order=True) @@ -237,7 +327,7 @@ def test_bench_command_one_cumulus_runtime(self): command='bench', runtime=['asset-hub-westend'], pallet=['pallet_assets'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None @@ -257,10 +347,11 @@ def test_bench_command_one_cumulus_runtime(self): call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), # Asset-hub-westend runtime calls call(get_mock_bench_output( - 'asset-hub-westend', - 'pallet_assets', - './cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', - header_path + runtime='asset-hub-westend', + pallets='pallet_assets', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', + header=header_path, + bench_flags='--flag7 --flag8' )), ] @@ -271,7 +362,7 @@ def test_bench_command_one_cumulus_runtime_xcm(self): command='bench', runtime=['asset-hub-westend'], pallet=['pallet_xcm_benchmarks::generic', 'pallet_assets'], - continue_on_fail=False, + fail_fast=True, quiet=False, clean=False, image=None @@ -291,23 +382,25 @@ def test_bench_command_one_cumulus_runtime_xcm(self): call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), # Asset-hub-westend runtime calls call(get_mock_bench_output( - 'asset-hub-westend', - 'pallet_xcm_benchmarks::generic', - './cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm', - header_path, - "cumulus/templates/xcm-bench-template.hbs" + runtime='asset-hub-westend', + pallets='pallet_xcm_benchmarks::generic', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm', + header=header_path, + bench_flags='--flag7 --flag8', + template="cumulus/templates/xcm-bench-template.hbs" )), call(get_mock_bench_output( - 'asset-hub-westend', - 'pallet_assets', - './cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', - header_path + runtime='asset-hub-westend', + pallets='pallet_assets', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', + header=header_path, + bench_flags='--flag7 --flag8' )), ] self.mock_system.assert_has_calls(expected_calls, any_order=True) - @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='fmt', continue_on_fail=False), [])) + @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='fmt'), [])) @patch('os.system', return_value=0) def test_fmt_command(self, mock_system, mock_parse_args): with patch('sys.exit') as mock_exit: @@ -317,7 +410,7 @@ def test_fmt_command(self, mock_system, mock_parse_args): mock_system.assert_any_call('cargo +nightly fmt') mock_system.assert_any_call('taplo format --config .config/taplo.toml') - @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='update-ui', continue_on_fail=False), [])) + @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='update-ui'), [])) @patch('os.system', return_value=0) def test_update_ui_command(self, mock_system, mock_parse_args): with patch('sys.exit') as mock_exit: @@ -326,7 +419,7 @@ def test_update_ui_command(self, mock_system, mock_parse_args): mock_exit.assert_not_called() mock_system.assert_called_with('sh ./scripts/update-ui-tests.sh') - @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='prdoc', continue_on_fail=False), [])) + @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='prdoc'), [])) @patch('os.system', return_value=0) def test_prdoc_command(self, mock_system, mock_parse_args): with patch('sys.exit') as mock_exit: @@ -336,4 +429,4 @@ def test_prdoc_command(self, mock_system, mock_parse_args): self.mock_generate_prdoc_main.assert_called_with(mock_parse_args.return_value[0]) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index d2a4baf12fa7..e3dd6224f29b 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -306,9 +306,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 @@ -405,14 +406,10 @@ function find_runtimes() { # output: none filter_version_from_input() { version=$1 - regex="(^v[0-9]+\.[0-9]+\.[0-9]+)$|(^v[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+)$" + regex="^(v)?[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$" if [[ $version =~ $regex ]]; then - if [ -n "${BASH_REMATCH[1]}" ]; then - echo "${BASH_REMATCH[1]}" - elif [ -n "${BASH_REMATCH[2]}" ]; then - echo "${BASH_REMATCH[2]}" - fi + echo $version else echo "Invalid version: $version" exit 1 @@ -462,7 +459,7 @@ function get_polkadot_node_version_from_code() { validate_stable_tag() { tag="$1" - pattern="^stable[0-9]{4}(-[0-9]+)?(-rc[0-9]+)?$" + pattern="^(polkadot-)?stable[0-9]{4}(-[0-9]+)?(-rc[0-9]+)?$" if [[ $tag =~ $pattern ]]; then echo $tag diff --git a/.github/scripts/generate-prdoc.py b/.github/scripts/generate-prdoc.py index f05d517a5802..780fa0012976 100644 --- a/.github/scripts/generate-prdoc.py +++ b/.github/scripts/generate-prdoc.py @@ -7,7 +7,7 @@ This will delete any prdoc that already exists for the PR if `--force` is passed. Usage: - python generate-prdoc.py --pr 1234 --audience "TODO" --bump "TODO" + python generate-prdoc.py --pr 1234 --audience node_dev --bump patch """ import argparse @@ -110,27 +110,35 @@ def yaml_multiline_string_presenter(dumper, data): yaml.add_representer(str, yaml_multiline_string_presenter) # parse_args is also used by cmd/cmd.py -def setup_parser(parser=None): +# if pr_required is False, then --pr is optional, as it can be derived from the PR comment body +def setup_parser(parser=None, pr_required=True): + allowed_audiences = ["runtime_dev", "runtime_user", "node_dev", "node_operator"] if parser is None: parser = argparse.ArgumentParser() - parser.add_argument("--pr", type=int, required=True, help="The PR number to generate the PrDoc for." ) - parser.add_argument("--audience", type=str, default="TODO", help="The audience of whom the changes may concern.") - parser.add_argument("--bump", type=str, default="TODO", help="A default bump level for all crates.") - parser.add_argument("--force", type=str, help="Whether to overwrite any existing PrDoc.") - + parser.add_argument("--pr", type=int, required=pr_required, help="The PR number to generate the PrDoc for.") + parser.add_argument("--audience", type=str, nargs='*', choices=allowed_audiences, default=["todo"], help="The audience of whom the changes may concern. Example: --audience runtime_dev node_dev") + parser.add_argument("--bump", type=str, default="major", choices=["patch", "minor", "major", "silent", "ignore", "no_change"], help="A default bump level for all crates. Example: --bump patch") + parser.add_argument("--force", action="store_true", help="Whether to overwrite any existing PrDoc.") return parser +def snake_to_title(s): + return ' '.join(word.capitalize() for word in s.split('_')) + def main(args): - force = True if (args.force or "false").lower() == "true" else False - print(f"Args: {args}, force: {force}") + print(f"Args: {args}, force: {args.force}") setup_yaml() try: - from_pr_number(args.pr, args.audience, args.bump, force) + # Convert snake_case audience arguments to title case + mapped_audiences = [snake_to_title(a) for a in args.audience] + if len(mapped_audiences) == 1: + mapped_audiences = mapped_audiences[0] + from_pr_number(args.pr, mapped_audiences, args.bump, args.force) return 0 except Exception as e: print(f"Error generating prdoc: {e}") return 1 if __name__ == "__main__": - args = setup_parser().parse_args() + parser = setup_parser() + args = parser.parse_args() main(args) diff --git a/.github/scripts/release/build-deb.sh b/.github/scripts/release/build-deb.sh new file mode 100755 index 000000000000..8dce621bb4de --- /dev/null +++ b/.github/scripts/release/build-deb.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -e + +PRODUCT=$1 +VERSION=$2 +PROFILE=${PROFILE:-production} + +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" + +cargo deb --profile $PROFILE --no-strip --no-build -p $PRODUCT --deb-version $VERSION + +deb=target/debian/$PRODUCT_*_amd64.deb + +cp $deb target/production/ diff --git a/.github/scripts/release/build-linux-release.sh b/.github/scripts/release/build-linux-release.sh new file mode 100755 index 000000000000..a6bd658d292a --- /dev/null +++ b/.github/scripts/release/build-linux-release.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# This is used to build our binaries: +# - polkadot +# - polkadot-parachain +# set -e + +BIN=$1 +PACKAGE=${2:-$BIN} + +PROFILE=${PROFILE:-production} +ARTIFACTS=/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/nul +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/release_lib.sh b/.github/scripts/release/release_lib.sh index 81a3c14edec8..f5032073b617 100644 --- a/.github/scripts/release/release_lib.sh +++ b/.github/scripts/release/release_lib.sh @@ -116,3 +116,24 @@ set_polkadot_parachain_binary_version() { commit_with_message "$MESSAGE" git_show_log "$MESSAGE" } + + +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 + + 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 + echo "Content to be uploaded:" + artifacts="artifacts/$product/" + ls "$artifacts" + aws s3 sync --acl public-read "$artifacts" "s3://releases.parity.io/polkadot/${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}" +} diff --git a/.github/workflows/build-misc.yml b/.github/workflows/build-misc.yml index 2a8e81b97878..a9b433a94b64 100644 --- a/.github/workflows/build-misc.yml +++ b/.github/workflows/build-misc.yml @@ -16,7 +16,6 @@ permissions: contents: read jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml @@ -38,11 +37,18 @@ jobs: - name: Build env: SUBSTRATE_RUNTIME_TARGET: riscv + id: required 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 + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' }} + 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 +68,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' }} + 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 new file mode 100644 index 000000000000..3aa1624096df --- /dev/null +++ b/.github/workflows/build-publish-eth-rpc.yml @@ -0,0 +1,79 @@ +name: Build and push ETH-RPC image + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review, labeled] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + IMAGE_NAME: "docker.io/paritypr/eth-rpc" + +jobs: + set-variables: + # This workaround sets the container image for each job using 'set-variables' job output. + # env variables don't work for PR from forks, so we need to use outputs. + runs-on: ubuntu-latest + outputs: + VERSION: ${{ steps.version.outputs.VERSION }} + steps: + - name: Define version + id: version + run: | + export COMMIT_SHA=${{ github.sha }} + export COMMIT_SHA_SHORT=${COMMIT_SHA:0:8} + export REF_NAME=${{ github.ref_name }} + export REF_SLUG=${REF_NAME//\//_} + VERSION=${REF_SLUG}-${COMMIT_SHA_SHORT} + echo "VERSION=${REF_SLUG}-${COMMIT_SHA_SHORT}" >> $GITHUB_OUTPUT + echo "set VERSION=${VERSION}" + + build_docker: + name: Build docker image + runs-on: parity-large + needs: [set-variables] + env: + VERSION: ${{ needs.set-variables.outputs.VERSION }} + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./substrate/frame/revive/rpc/Dockerfile + push: false + tags: | + ${{ env.IMAGE_NAME }}:${{ env.VERSION }} + + build_push_docker: + name: Build and push docker image + runs-on: parity-large + if: github.ref == 'refs/heads/master' + needs: [set-variables] + env: + VERSION: ${{ needs.set-variables.outputs.VERSION }} + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.PARITYPR_DOCKERHUB_USERNAME }} + password: ${{ secrets.PARITYPR_DOCKERHUB_PASSWORD }} + + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./substrate/frame/revive/rpc/Dockerfile + push: true + tags: | + ${{ env.IMAGE_NAME }}:${{ env.VERSION }} diff --git a/.github/workflows/build-publish-images.yml b/.github/workflows/build-publish-images.yml index 3a9f60761863..874b5d37469c 100644 --- a/.github/workflows/build-publish-images.yml +++ b/.github/workflows/build-publish-images.yml @@ -15,7 +15,6 @@ env: COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} jobs: - # # # @@ -24,7 +23,7 @@ jobs: if: contains(github.event.label.name, 'GHA-migration') || contains(github.event.pull_request.labels.*.name, 'GHA-migration') uses: ./.github/workflows/reusable-preflight.yml -### Build ######################## + ### Build ######################## # # @@ -240,7 +239,7 @@ jobs: with: # tldr: we need to checkout the branch HEAD explicitly because of our dynamic versioning approach while building the substrate binary # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 - ref: ${{ github.head_ref || github.ref_name }} + ref: ${{ github.head_ref || github.ref_name }} - name: build run: | mkdir -p ./artifacts/substrate/ @@ -299,14 +298,14 @@ jobs: path: artifacts.tar retention-days: 1 -### Publish ######################## + ### Publish ######################## # # # build-push-image-test-parachain: needs: [preflight, build-test-parachain] - runs-on: arc-runners-polkadot-sdk + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -330,7 +329,7 @@ jobs: # build-push-image-polkadot-debug: needs: [preflight, build-linux-stable] - runs-on: arc-runners-polkadot-sdk + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -349,13 +348,12 @@ jobs: image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/polkadot-debug" dockerfile: "docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile" - # # # build-push-image-colander: needs: [preflight, build-test-collators] - runs-on: arc-runners-polkadot-sdk + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -374,13 +372,12 @@ jobs: image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/colander" dockerfile: "docker/dockerfiles/collator_injected.Dockerfile" - # # # build-push-image-malus: needs: [preflight, build-malus] - runs-on: arc-runners-polkadot-sdk + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -399,13 +396,12 @@ jobs: image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/malus" dockerfile: "docker/dockerfiles/malus_injected.Dockerfile" - # # # build-push-image-substrate-pr: needs: [preflight, build-linux-substrate] - runs-on: arc-runners-polkadot-sdk + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -424,15 +420,20 @@ jobs: image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/substrate" dockerfile: "docker/dockerfiles/substrate_injected.Dockerfile" - # # # # unlike other images, bridges+zombienet image is based on Zombienet image that pulls required binaries # from other fresh images (polkadot and cumulus) build-push-image-bridges-zombienet-tests: - needs: [preflight, build-linux-stable, build-linux-stable-cumulus, prepare-bridges-zombienet-artifacts] - runs-on: arc-runners-polkadot-sdk + needs: + [ + preflight, + build-linux-stable, + build-linux-stable-cumulus, + prepare-bridges-zombienet-artifacts, + ] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -443,24 +444,24 @@ jobs: name: build-linux-stable-${{ needs.preflight.outputs.SOURCE_REF_NAME }} - name: tar run: | - tar -xvf artifacts.tar - rm artifacts.tar + tar -xvf artifacts.tar + rm artifacts.tar - uses: actions/download-artifact@v4.1.8 with: name: build-linux-stable-cumulus-${{ needs.preflight.outputs.SOURCE_REF_NAME }} - name: tar run: | - tar -xvf artifacts.tar - rm artifacts.tar + tar -xvf artifacts.tar + rm artifacts.tar - uses: actions/download-artifact@v4.1.8 with: name: prepare-bridges-zombienet-artifacts-${{ needs.preflight.outputs.SOURCE_REF_NAME }} - name: tar run: | - tar -xvf artifacts.tar - rm artifacts.tar + tar -xvf artifacts.tar + rm artifacts.tar - name: build and push image uses: ./.github/actions/build-push-image @@ -468,13 +469,12 @@ jobs: image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/bridges-zombienet-tests" dockerfile: "docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile" - # # # build-push-image-polkadot-parachain-debug: needs: [preflight, build-linux-stable-cumulus] - runs-on: arc-runners-polkadot-sdk + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} timeout-minutes: 60 steps: - name: Checkout @@ -491,4 +491,4 @@ jobs: uses: ./.github/actions/build-push-image with: image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/polkadot-parachain-debug" - dockerfile: "docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile" \ No newline at end of file + dockerfile: "docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile" diff --git a/.github/workflows/check-cargo-check-runtimes.yml b/.github/workflows/check-cargo-check-runtimes.yml index 7e9f0dc77b7c..376c34d1f25f 100644 --- a/.github/workflows/check-cargo-check-runtimes.yml +++ b/.github/workflows/check-cargo-check-runtimes.yml @@ -7,11 +7,12 @@ concurrency: on: pull_request: types: [opened, synchronize, reopened, ready_for_review] + paths: + - "cumulus/parachains/runtimes/*" # Jobs in this workflow depend on each other, only for limiting peak amount of spawned workers jobs: - preflight: uses: ./.github/workflows/reusable-preflight.yml @@ -109,7 +110,6 @@ jobs: - check-runtime-coretime - check-runtime-bridge-hubs - check-runtime-contracts - - check-runtime-starters - check-runtime-testing if: always() && !cancelled() steps: diff --git a/.github/workflows/check-features.yml b/.github/workflows/check-features.yml deleted file mode 100644 index d8e2f72c0ffd..000000000000 --- a/.github/workflows/check-features.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Check Features - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - check-features: - runs-on: ubuntu-latest - steps: - - name: Fetch latest code - uses: actions/checkout@v4 - - name: Check - uses: hack-ink/cargo-featalign-action@bea88a864d6ca7d0c53c26f1391ce1d431dc7f34 # v0.1.1 - with: - crate: templates/parachain/runtime/ - features: std,runtime-benchmarks,try-runtime - ignore: sc-executor - default-std: true diff --git a/.github/workflows/check-frame-omni-bencher.yml b/.github/workflows/check-frame-omni-bencher.yml index 9b01311aa69c..b47c9d49feaf 100644 --- a/.github/workflows/check-frame-omni-bencher.yml +++ b/.github/workflows/check-frame-omni-bencher.yml @@ -16,14 +16,11 @@ env: ARTIFACTS_NAME: frame-omni-bencher-artifacts jobs: - preflight: - # TODO: remove once migration is complete or this workflow is fully stable - if: contains(github.event.label.name, 'GHA-migration') uses: ./.github/workflows/reusable-preflight.yml quick-benchmarks-omni: - runs-on: ${{ needs.preflight.outputs.RUNNER }} + runs-on: ${{ needs.preflight.outputs.RUNNER_BENCHMARK }} needs: [preflight] if: ${{ needs.preflight.outputs.changes_rust }} env: @@ -31,6 +28,7 @@ jobs: RUST_BACKTRACE: "full" WASM_BUILD_NO_COLOR: 1 WASM_BUILD_RUSTFLAGS: "-C debug-assertions" + RUST_LOG: "frame_omni_bencher=info,polkadot_sdk_frame=info" timeout-minutes: 30 container: image: ${{ needs.preflight.outputs.IMAGE }} @@ -38,53 +36,79 @@ 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' }} + 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 + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + timeout-minutes: 30 + outputs: + runtime: ${{ steps.runtime.outputs.runtime }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + name: Extract runtimes from matrix + steps: + - uses: actions/checkout@v4 + - id: runtime + run: | + RUNTIMES=$(jq '[.[] | select(.package != null)]' .github/workflows/runtimes-matrix.json) + + RUNTIMES=$(echo $RUNTIMES | jq -c .) + echo "runtime=$RUNTIMES" + echo "runtime=$RUNTIMES" >> $GITHUB_OUTPUT run-frame-omni-bencher: - runs-on: ${{ needs.preflight.outputs.RUNNER }} - needs: [preflight] # , build-frame-omni-bencher ] + runs-on: ${{ needs.preflight.outputs.RUNNER_BENCHMARK }} + needs: [preflight, runtime-matrix] if: ${{ needs.preflight.outputs.changes_rust }} timeout-minutes: 30 strategy: fail-fast: false # keep running other workflows even if one fails, to see the logs of all possible failures matrix: - runtime: - [ - westend-runtime, - rococo-runtime, - asset-hub-rococo-runtime, - asset-hub-westend-runtime, - bridge-hub-rococo-runtime, - bridge-hub-westend-runtime, - collectives-westend-runtime, - coretime-rococo-runtime, - coretime-westend-runtime, - people-rococo-runtime, - people-westend-runtime, - glutton-westend-runtime, - ] + runtime: ${{ fromJSON(needs.runtime-matrix.outputs.runtime) }} container: image: ${{ needs.preflight.outputs.IMAGE }} env: - PACKAGE_NAME: ${{ matrix.runtime }} + PACKAGE_NAME: ${{ matrix.runtime.package }} + FLAGS: ${{ matrix.runtime.bench_flags }} + RUST_LOG: "frame_omni_bencher=info,polkadot_sdk_frame=info" steps: - name: Checkout 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 - forklift cargo build --release --locked -p $PACKAGE_NAME -p frame-omni-bencher --features runtime-benchmarks + forklift cargo build --release --locked -p $PACKAGE_NAME -p frame-omni-bencher --features=${{ matrix.runtime.bench_features }} --quiet echo "Running short benchmarking for PACKAGE_NAME=$PACKAGE_NAME and RUNTIME_BLOB_PATH=$RUNTIME_BLOB_PATH" ls -lrt $RUNTIME_BLOB_PATH - ./target/release/frame-omni-bencher v1 benchmark pallet --runtime $RUNTIME_BLOB_PATH --all --steps 2 --repeat 1 + + 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' }} + 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 - needs: run-frame-omni-bencher + needs: [quick-benchmarks-omni, run-frame-omni-bencher] if: always() && !cancelled() steps: - run: | diff --git a/.github/workflows/check-getting-started.yml b/.github/workflows/check-getting-started.yml index b43db33c63bf..0661fa144348 100644 --- a/.github/workflows/check-getting-started.yml +++ b/.github/workflows/check-getting-started.yml @@ -6,7 +6,7 @@ name: Check the getting-started.sh script # # There are two jobs inside. # One for systems that can run in a docker container, and one for macOS. -# +# # Each job consists of: # 1. Some necessary prerequisites for the workflow itself. # 2. A first pass of the script, which will install dependencies and clone a template. @@ -24,10 +24,10 @@ name: Check the getting-started.sh script on: pull_request: paths: - - '.github/workflows/check-getting-started.yml' - - 'scripts/getting-started.sh' + - ".github/workflows/check-getting-started.yml" + - "scripts/getting-started.sh" schedule: - - cron: '0 5 * * *' + - cron: "0 5 * * *" workflow_dispatch: concurrency: @@ -60,7 +60,7 @@ jobs: container: opensuse/tumbleweed template: solochain shell: sh - runs-on: arc-runners-polkadot-sdk-beefy + runs-on: parity-large container: ${{ matrix.container }}:latest steps: # A minimal amount of prerequisites required before we can run the actual getting-started script, @@ -116,7 +116,7 @@ jobs: expect "start with one of the templates" { send "y\r" } - + expect -re "(.)\\) ${{ matrix.template }} template" { send "$expect_out(1,string)\r" } @@ -150,7 +150,7 @@ jobs: expect "start with one of the templates" { send "y\r" } - + expect -re "(.)\\) ${{ matrix.template }} template" { send "$expect_out(1,string)\r" expect "directory already exists" {} @@ -227,7 +227,7 @@ jobs: expect "start with one of the templates" { send "y\r" } - + expect -re "(.)\\) ${{ matrix.template }} template" { send "$expect_out(1,string)\r" } @@ -267,7 +267,7 @@ jobs: expect "start with one of the templates" { send "y\r" } - + expect -re "(.)\\) ${{ matrix.template }} template" { send "$expect_out(1,string)\r" expect "directory already exists" {} diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 6ec35840608c..d5c91e7f55e2 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -12,6 +12,7 @@ on: jobs: check-labels: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Check labels env: 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 0ebd33d417af..dd9d3eaf824f 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -20,6 +20,7 @@ permissions: jobs: link-checker: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Restore lychee cache uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v3.3.2 (7. Sep 2023) @@ -32,7 +33,7 @@ jobs: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.0 (22. Sep 2023) - name: Lychee link checker - uses: lycheeverse/lychee-action@2b973e86fc7b1f6b36a93795fe2c9c6ae1118621 # for v1.9.1 (10. Jan 2024) + uses: lycheeverse/lychee-action@7cd0af4c74a61395d455af97419279d86aafaede # for v1.9.1 (10. Jan 2024) with: args: >- --config .config/lychee.toml diff --git a/.github/workflows/check-prdoc.yml b/.github/workflows/check-prdoc.yml index fc2824770225..8af1dd8cef70 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -21,6 +21,7 @@ env: jobs: check-prdoc: runs-on: ubuntu-latest + timeout-minutes: 10 if: github.event.pull_request.number != '' steps: - name: Checkout repo diff --git a/.github/workflows/check-runtime-migration.yml b/.github/workflows/check-runtime-migration.yml index 8d30e752b115..9866ae18b98a 100644 --- a/.github/workflows/check-runtime-migration.yml +++ b/.github/workflows/check-runtime-migration.yml @@ -36,68 +36,47 @@ jobs: network: [ westend, - rococo, asset-hub-westend, - asset-hub-rococo, bridge-hub-westend, - bridge-hub-rococo, - contracts-rococo, collectives-westend, - coretime-rococo, + coretime-westend, ] include: - network: westend package: westend-runtime wasm: westend_runtime.compact.compressed.wasm uri: "wss://try-runtime-westend.polkadot.io:443" - subcommand_extra_args: "--no-weight-warnings" - command_extra_args: "" - - network: rococo - package: rococo-runtime - wasm: rococo_runtime.compact.compressed.wasm - uri: "wss://try-runtime-rococo.polkadot.io:443" - subcommand_extra_args: "--no-weight-warnings" + subcommand_extra_args: "--no-weight-warnings --blocktime 6000" command_extra_args: "" - network: asset-hub-westend package: asset-hub-westend-runtime wasm: asset_hub_westend_runtime.compact.compressed.wasm uri: "wss://westend-asset-hub-rpc.polkadot.io:443" - subcommand_extra_args: "" - command_extra_args: "" - - network: "asset-hub-rococo" - package: "asset-hub-rococo-runtime" - wasm: "asset_hub_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-asset-hub-rpc.polkadot.io:443" - subcommand_extra_args: "" + subcommand_extra_args: " --blocktime 6000" command_extra_args: "" - - network: "bridge-hub-westend" - package: "bridge-hub-westend-runtime" - wasm: "bridge_hub_westend_runtime.compact.compressed.wasm" + - network: bridge-hub-westend + package: bridge-hub-westend-runtime + wasm: bridge_hub_westend_runtime.compact.compressed.wasm uri: "wss://westend-bridge-hub-rpc.polkadot.io:443" - - network: "bridge-hub-rococo" - package: "bridge-hub-rococo-runtime" - wasm: "bridge_hub_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-bridge-hub-rpc.polkadot.io:443" - - network: "contracts-rococo" - package: "contracts-rococo-runtime" - wasm: "contracts_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-contracts-rpc.polkadot.io:443" - - network: "collectives-westend" - package: "collectives-westend-runtime" - wasm: "collectives_westend_runtime.compact.compressed.wasm" + subcommand_extra_args: " --blocktime 6000" + - network: collectives-westend + package: collectives-westend-runtime + wasm: collectives_westend_runtime.compact.compressed.wasm uri: "wss://westend-collectives-rpc.polkadot.io:443" command_extra_args: "--disable-spec-name-check" - - network: "coretime-rococo" - package: "coretime-rococo-runtime" - wasm: "coretime_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-coretime-rpc.polkadot.io:443" + subcommand_extra_args: " --blocktime 6000" + - network: coretime-westend + package: coretime-westend-runtime + wasm: coretime_westend_runtime.compact.compressed.wasm + uri: "wss://westend-coretime-rpc.polkadot.io:443" + subcommand_extra_args: " --blocktime 6000" steps: - name: Checkout uses: actions/checkout@v4 - name: Download CLI run: | - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.7.0/try-runtime-x86_64-unknown-linux-musl -o try-runtime + curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.8.0/try-runtime-x86_64-unknown-linux-musl -o try-runtime chmod +x ./try-runtime echo "Using try-runtime-cli version:" ./try-runtime --version @@ -122,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 b5866e0ce414..78602410cdf6 100644 --- a/.github/workflows/check-semver.yml +++ b/.github/workflows/check-semver.yml @@ -4,6 +4,7 @@ on: pull_request: types: [opened, synchronize, reopened, ready_for_review] workflow_dispatch: + merge_group: concurrency: group: check-semver-${{ github.event.pull_request.number || github.ref }} @@ -13,10 +14,14 @@ env: TOOLCHAIN: nightly-2024-06-01 jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml check-semver: runs-on: ubuntu-latest + timeout-minutes: 90 + needs: [preflight] container: - image: docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408 + image: ${{ needs.preflight.outputs.IMAGE }} steps: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 with: @@ -36,10 +41,6 @@ jobs: run: | echo "This is a backport into stable." - wget -q https://github.com/cli/cli/releases/download/v2.51.0/gh_2.51.0_linux_amd64.tar.gz -O gh.tar.gz && \ - tar -xzf gh.tar.gz && mv gh_2.51.0_linux_amd64/bin/gh /usr/local/bin/gh && rm gh.tar.gz - chmod +x /usr/local/bin/gh - cat > msg.txt <> $GITHUB_ENV - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: cache-on-failure: true diff --git a/.github/workflows/checks-quick.yml b/.github/workflows/checks-quick.yml index eefe36d9791d..4fcaf80c83fc 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' }} + 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 @@ -102,7 +108,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 +178,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 +219,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 0793c31dbb87..c240504fa1e7 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: | - forklift cargo clippy --all-targets --locked --workspace --quiet - forklift cargo clippy --all-targets --all-features --locked --workspace --quiet + 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' }} + 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' }} + 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' }} + 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 0c9c48a123b0..525ab0c0fc23 100644 --- a/.github/workflows/cmd.yml +++ b/.github/workflows/cmd.yml @@ -152,15 +152,15 @@ jobs: id: get-pr-comment with: text: ${{ github.event.comment.body }} - regex: '^(\/cmd )([-\/\s\w.=:]+)$' # see explanation in docs/contributor/commands-readme.md#examples + regex: "^(\\/cmd )([-\\/\\s\\w.=:]+)$" # see explanation in docs/contributor/commands-readme.md#examples - name: Save output of help id: help env: CMD: ${{ steps.get-pr-comment.outputs.group2 }} # to avoid "" around the command run: | - echo 'help<> $GITHUB_OUTPUT python3 -m pip install -r .github/scripts/generate-prdoc.requirements.txt + echo 'help<> $GITHUB_OUTPUT python3 .github/scripts/cmd/cmd.py $CMD >> $GITHUB_OUTPUT echo 'EOF' >> $GITHUB_OUTPUT @@ -283,6 +283,7 @@ 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 }} steps: @@ -291,7 +292,18 @@ jobs: id: get-pr-comment with: text: ${{ github.event.comment.body }} - regex: '^(\/cmd )([-\/\s\w.=:]+)$' # see explanation in docs/contributor/commands-readme.md#examples + regex: "^(\\/cmd )([-\\/\\s\\w.=:]+)$" # see explanation in docs/contributor/commands-readme.md#examples + + # In order to run prdoc without specifying the PR number, we need to add the PR number as an argument automatically + - name: Prepare PR Number argument + id: pr-arg + run: | + CMD="${{ steps.get-pr-comment.outputs.group2 }}" + if echo "$CMD" | grep -q "prdoc" && ! echo "$CMD" | grep -qE "\-\-pr[[:space:]=][0-9]+"; then + echo "arg=--pr ${{ github.event.issue.number }}" >> $GITHUB_OUTPUT + else + echo "arg=" >> $GITHUB_OUTPUT + fi - name: Build workflow link if: ${{ !contains(github.event.comment.body, '--quiet') }} @@ -314,7 +326,8 @@ jobs: echo "run_url=$runLink" >> $GITHUB_OUTPUT - name: Comment PR (Start) - if: ${{ !contains(github.event.comment.body, '--quiet') }} + # No need to comment on prdoc start or if --quiet + if: ${{ !contains(github.event.comment.body, '--quiet') && !contains(github.event.comment.body, 'prdoc') }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -344,17 +357,35 @@ jobs: id: cmd env: CMD: ${{ steps.get-pr-comment.outputs.group2 }} # to avoid "" around the command + PR_ARG: ${{ steps.pr-arg.outputs.arg }} run: | - echo "Running command: '$CMD' on '${{ needs.set-image.outputs.RUNNER }}' runner, container: '${{ needs.set-image.outputs.IMAGE }}'" + echo "Running command: '$CMD $PR_ARG' on '${{ needs.set-image.outputs.RUNNER }}' runner, container: '${{ needs.set-image.outputs.IMAGE }}'" echo "RUST_NIGHTLY_VERSION: $RUST_NIGHTLY_VERSION" # Fixes "detected dubious ownership" error in the ci git config --global --add safe.directory '*' git remote -v python3 -m pip install -r .github/scripts/generate-prdoc.requirements.txt - python3 .github/scripts/cmd/cmd.py $CMD + python3 .github/scripts/cmd/cmd.py $CMD $PR_ARG git status git diff + if [ -f /tmp/cmd/command_output.log ]; then + CMD_OUTPUT=$(cat /tmp/cmd/command_output.log) + # export to summary to display in the PR + echo "$CMD_OUTPUT" >> $GITHUB_STEP_SUMMARY + # should be multiline, otherwise it captures the first line only + echo 'cmd_output<> $GITHUB_OUTPUT + echo "$CMD_OUTPUT" >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + fi + + - name: Upload command output + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: command-output + path: /tmp/cmd/command_output.log + - name: Commit changes run: | if [ -n "$(git status --porcelain)" ]; then @@ -395,39 +426,55 @@ jobs: } >> $GITHUB_OUTPUT - name: Comment PR (End) - if: ${{ !failure() && !contains(github.event.comment.body, '--quiet') }} + # No need to comment on prdoc success or --quiet + if: ${{ !failure() && !contains(github.event.comment.body, '--quiet') && !contains(github.event.comment.body, 'prdoc') }} uses: actions/github-script@v7 env: SUBWEIGHT: "${{ steps.subweight.outputs.result }}" + CMD_OUTPUT: "${{ steps.cmd.outputs.cmd_output }}" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | let runUrl = ${{ steps.build-link.outputs.run_url }} let subweight = process.env.SUBWEIGHT; + let cmdOutput = process.env.CMD_OUTPUT; + console.log(cmdOutput); - let subweightCollapsed = subweight + let subweightCollapsed = subweight.trim() !== '' ? `
\n\nSubweight results:\n\n${subweight}\n\n
` : ''; + let cmdOutputCollapsed = cmdOutput.trim() !== '' + ? `
\n\nCommand output:\n\n${cmdOutput}\n\n
` + : ''; + github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has finished ✅ [See logs here](${runUrl})${subweightCollapsed}` + body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has finished ✅ [See logs here](${runUrl})${subweightCollapsed}${cmdOutputCollapsed}` }) - name: Comment PR (Failure) if: ${{ failure() && !contains(github.event.comment.body, '--quiet') }} uses: actions/github-script@v7 + env: + CMD_OUTPUT: "${{ steps.cmd.outputs.cmd_output }}" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | let jobUrl = ${{ steps.build-link.outputs.job_url }} + let cmdOutput = process.env.CMD_OUTPUT; + + let cmdOutputCollapsed = cmdOutput.trim() !== '' + ? `
\n\nCommand output:\n\n${cmdOutput}\n\n
` + : ''; + github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has failed ❌! [See logs here](${jobUrl})` + body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has failed ❌! [See logs here](${jobUrl})${cmdOutputCollapsed}` }) - name: Add 😕 reaction on failure diff --git a/.github/workflows/command-backport.yml b/.github/workflows/command-backport.yml index 5b32f954d0cd..8f23bcd75f01 100644 --- a/.github/workflows/command-backport.yml +++ b/.github/workflows/command-backport.yml @@ -4,12 +4,13 @@ on: # This trigger can be problematic, see: https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/ # In our case it is fine since we only run it on merged Pull Requests and do not execute any of the repo code itself. pull_request_target: - types: [ closed, labeled ] + types: [closed, labeled] permissions: contents: write # so it can comment pull-requests: write # so it can create pull requests issues: write + actions: write # It may have to backport changes to the CI as well. jobs: backport: @@ -65,7 +66,7 @@ jobs: with: script: | const pullNumbers = '${{ steps.backport.outputs.created_pull_numbers }}'.split(' '); - + for (const pullNumber of pullNumbers) { await github.rest.issues.addLabels({ issue_number: parseInt(pullNumber), @@ -83,7 +84,7 @@ jobs: script: | const pullNumbers = '${{ steps.backport.outputs.created_pull_numbers }}'.split(' '); const reviewer = '${{ github.event.pull_request.user.login }}'; - + for (const pullNumber of pullNumbers) { await github.pulls.createReviewRequest({ owner: context.repo.owner, diff --git a/.github/workflows/command-prdoc.yml b/.github/workflows/command-prdoc.yml index 2154c8a987f2..7022e8e0e006 100644 --- a/.github/workflows/command-prdoc.yml +++ b/.github/workflows/command-prdoc.yml @@ -14,7 +14,7 @@ on: required: true options: - "TODO" - - "no change" + - "no_change" - "patch" - "minor" - "major" @@ -25,18 +25,15 @@ on: required: true options: - "TODO" - - "Runtime Dev" - - "Runtime User" - - "Node Dev" - - "Node Operator" + - "runtime_dev" + - "runtime_user" + - "node_dev" + - "node_operator" overwrite: - type: choice + type: boolean description: Overwrite existing PrDoc - default: "true" + default: true required: true - options: - - "true" - - "false" concurrency: group: command-prdoc @@ -81,4 +78,4 @@ jobs: with: commit_message: Add PrDoc (auto generated) branch: ${{ steps.gh.outputs.branch }} - file_pattern: 'prdoc/*.prdoc' + file_pattern: "prdoc/*.prdoc" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8fe3e80e628d..cc84e7f9ad3b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,40 +14,38 @@ concurrency: jobs: preflight: - if: contains(github.event.label.name, 'GHA-migration') uses: ./.github/workflows/reusable-preflight.yml - test-rustdoc: - runs-on: ${{ needs.preflight.outputs.RUNNER }} - if: ${{ needs.preflight.outputs.changes_rust }} - needs: [preflight] - container: - image: ${{ needs.preflight.outputs.IMAGE }} - steps: - - uses: actions/checkout@v4 - - run: forklift cargo doc --workspace --all-features --no-deps - env: - SKIP_WASM_BUILD: 1 test-doc: runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 needs: [preflight] container: image: ${{ needs.preflight.outputs.IMAGE }} 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' }} + 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 }} + timeout-minutes: 40 if: ${{ needs.preflight.outputs.changes_rust }} - needs: [preflight, test-rustdoc] + needs: [preflight] container: image: ${{ needs.preflight.outputs.IMAGE }} 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" @@ -70,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' }} + 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 @@ -88,6 +92,23 @@ jobs: retention-days: 1 if-no-files-found: error + confirm-required-jobs-passed: + runs-on: ubuntu-latest + name: All docs jobs passed + # If any new job gets added, be sure to add it to this array + needs: [test-doc, build-rustdoc, build-implementers-guide] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi + publish-rustdoc: if: github.ref == 'refs/heads/master' runs-on: ubuntu-latest @@ -121,13 +142,30 @@ jobs: - run: mkdir -p book - name: Move book files run: mv /tmp/book/html/* book/ - - name: Push to GH-Pages branch - uses: github-actions-x/commit@v2.9 - with: - github-token: ${{ steps.app-token.outputs.token }} - push-branch: "gh-pages" - commit-message: "___Updated docs for ${{ github.head_ref || github.ref_name }}___" - force-add: "true" - files: ${{ github.head_ref || github.ref_name }}/ book/ - name: devops-parity - email: devops-team@parity.io + - name: Push changes to gh-pages + env: + TOKEN: ${{ steps.app-token.outputs.token }} + APP_NAME: "paritytech-upd-ghpages-polkadotsdk" + REF_NAME: ${{ github.head_ref || github.ref_name }} + Green: "\e[32m" + NC: "\e[0m" + run: | + echo "${Green}Git add${NC}" + git add book/ + git add ${REF_NAME}/ + + echo "${Green}git status | wc -l${NC}" + git status | wc -l + + echo "${Green}Add new remote with gh app token${NC}" + git remote set-url origin $(git config remote.origin.url | sed "s/github.com/${APP_NAME}:${TOKEN}@github.com/g") + + echo "${Green}Remove http section that causes issues with gh app auth token${NC}" + sed -i.bak '/\[http/d' ./.git/config + sed -i.bak '/extraheader/d' ./.git/config + + echo "${Green}Git push${NC}" + git config user.email "ci@parity.io" + git config user.name "${APP_NAME}" + git commit --amend -m "___Updated docs" || echo "___Nothing to commit___" + git push origin gh-pages --force diff --git a/.github/workflows/fork-sync-action.yml b/.github/workflows/fork-sync-action.yml index 69e9e93bf54b..50774e910527 100644 --- a/.github/workflows/fork-sync-action.yml +++ b/.github/workflows/fork-sync-action.yml @@ -1,5 +1,5 @@ # This Workflow is not supposed to run in the paritytech/polkadot-sdk repo. -# This Workflow is supposed to run only in the forks of the repo, +# This Workflow is supposed to run only in the forks of the repo, # paritytech-release/polkadot-sdk specifically, # to automatically maintain the critical fork synced with the upstream. # This Workflow should be always disabled in the paritytech/polkadot-sdk repo. @@ -11,10 +11,10 @@ on: workflow_dispatch: jobs: - job_sync_branches: - uses: paritytech-release/sync-workflows/.github/workflows/sync-with-upstream.yml@latest - with: - fork_writer_app_id: ${{ vars.UPSTREAM_CONTENT_SYNC_APP_ID}} - fork_owner: ${{ vars.RELEASE_ORG}} - secrets: - fork_writer_app_key: ${{ secrets.UPSTREAM_CONTENT_SYNC_APP_KEY }} + job_sync_branches: + uses: paritytech-release/sync-workflows/.github/workflows/sync-with-upstream.yml@main + with: + fork_writer_app_id: ${{ vars.UPSTREAM_CONTENT_SYNC_APP_ID}} + fork_owner: ${{ vars.RELEASE_ORG}} + secrets: + fork_writer_app_key: ${{ secrets.UPSTREAM_CONTENT_SYNC_APP_KEY }} diff --git a/.github/workflows/misc-sync-templates.yml b/.github/workflows/misc-sync-templates.yml index b5db0538569b..7ff0705fe249 100644 --- a/.github/workflows/misc-sync-templates.yml +++ b/.github/workflows/misc-sync-templates.yml @@ -83,6 +83,12 @@ jobs: homepage = "https://paritytech.github.io/polkadot-sdk/" [workspace] + EOF + + [ ${{ matrix.template }} != "solochain" ] && echo "# Leave out the node compilation from regular template usage." \ + && echo "\"default-members\" = [\"pallets/template\", \"runtime\"]" >> Cargo.toml + [ ${{ matrix.template }} == "solochain" ] && echo "# The node isn't yet replaceable by Omni Node." + cat << EOF >> Cargo.toml members = [ "node", "pallets/template", diff --git a/.github/workflows/publish-check-crates.yml b/.github/workflows/publish-check-crates.yml index a5af04118572..3fad3b641474 100644 --- a/.github/workflows/publish-check-crates.yml +++ b/.github/workflows/publish-check-crates.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: cache-on-failure: true diff --git a/.github/workflows/publish-claim-crates.yml b/.github/workflows/publish-claim-crates.yml index f9bc6ce4daea..37bf06bb82d8 100644 --- a/.github/workflows/publish-claim-crates.yml +++ b/.github/workflows/publish-claim-crates.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: cache-on-failure: true diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index 195c14dbd5ab..0be671185c70 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-10_rc-automation.yml @@ -12,7 +12,7 @@ on: workflow_dispatch: inputs: version: - description: Current release/rc version in format vX.X.X + description: Current release/rc version in format polkadot-stableYYMM jobs: tag_rc: @@ -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' }} @@ -41,7 +75,7 @@ jobs: if [[ -z "${{ inputs.version }}" ]]; then version=v$(get_polkadot_node_version_from_code) else - version=$(filter_version_from_input ${{ inputs.version }}) + version=$(validate_stable_tag ${{ inputs.version }}) fi echo "$version" echo "version=$version" >> $GITHUB_OUTPUT @@ -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-30_publish_release_draft.yml b/.github/workflows/release-30_publish_release_draft.yml index dd6a111d67e8..376f5fbce909 100644 --- a/.github/workflows/release-30_publish_release_draft.yml +++ b/.github/workflows/release-30_publish_release_draft.yml @@ -5,6 +5,7 @@ on: 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 workflow_dispatch: inputs: @@ -25,7 +26,7 @@ jobs: build-runtimes: uses: "./.github/workflows/release-srtool.yml" with: - excluded_runtimes: "substrate-test bp cumulus-test kitchensink minimal-template parachain-template penpal polkadot-test seedling shell frame-try sp solochain-template" + 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: @@ -33,7 +34,7 @@ jobs: strategy: matrix: # Tuples of [package, binary-name] - binary: [ [frame-omni-bencher, frame-omni-bencher], [staging-chain-spec-builder, chain-spec-builder] ] + 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 @@ -70,7 +71,7 @@ jobs: - 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 @@ -79,30 +80,27 @@ jobs: env: RUSTC_STABLE: ${{ needs.get-rust-versions.outputs.rustc-stable }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ASSET_HUB_ROCOCO_DIGEST: ${{ github.workspace}}/asset-hub-rococo-runtime/asset-hub-rococo-srtool-digest.json ASSET_HUB_WESTEND_DIGEST: ${{ github.workspace}}/asset-hub-westend-runtime/asset-hub-westend-srtool-digest.json - BRIDGE_HUB_ROCOCO_DIGEST: ${{ github.workspace}}/bridge-hub-rococo-runtime/bridge-hub-rococo-srtool-digest.json BRIDGE_HUB_WESTEND_DIGEST: ${{ github.workspace}}/bridge-hub-westend-runtime/bridge-hub-westend-srtool-digest.json COLLECTIVES_WESTEND_DIGEST: ${{ github.workspace}}/collectives-westend-runtime/collectives-westend-srtool-digest.json - CONTRACTS_ROCOCO_DIGEST: ${{ github.workspace}}/contracts-rococo-runtime/contracts-rococo-srtool-digest.json - CORETIME_ROCOCO_DIGEST: ${{ github.workspace}}/coretime-rococo-runtime/coretime-rococo-srtool-digest.json CORETIME_WESTEND_DIGEST: ${{ github.workspace}}/coretime-westend-runtime/coretime-westend-srtool-digest.json GLUTTON_WESTEND_DIGEST: ${{ github.workspace}}/glutton-westend-runtime/glutton-westend-srtool-digest.json - PEOPLE_ROCOCO_DIGEST: ${{ github.workspace}}/people-rococo-runtime/people-rococo-srtool-digest.json PEOPLE_WESTEND_DIGEST: ${{ github.workspace}}/people-westend-runtime/people-westend-srtool-digest.json - ROCOCO_DIGEST: ${{ github.workspace}}/rococo-runtime/rococo-srtool-digest.json WESTEND_DIGEST: ${{ github.workspace}}/westend-runtime/westend-srtool-digest.json + shell: bash run: | . ./.github/scripts/common/lib.sh export REF1=$(get_latest_release_tag) if [[ -z "${{ inputs.version }}" ]]; then export REF2="${{ github.ref_name }}" + echo "REF2: ${REF2}" else export REF2="${{ inputs.version }}" + echo "REF2: ${REF2}" fi echo "REL_TAG=$REF2" >> $GITHUB_ENV - export VERSION=$(echo "$REF2" | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/') + export VERSION=$(echo "$REF2" | sed -E 's/.*(stable[0-9]+).*$/\1/') ./scripts/release/build-changelogs.sh @@ -163,7 +161,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - binary: [frame-omni-bencher, chain-spec-builder] + binary: [frame-omni-bencher, chain-spec-builder, polkadot-omni-node] steps: - name: Download artifacts diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index dacfcc5995b7..627e53bacd88 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -26,6 +26,7 @@ on: type: choice options: - polkadot + - polkadot-omni-node - polkadot-parachain - chain-spec-builder @@ -80,9 +81,9 @@ jobs: validate-inputs: 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 }} + version: ${{ steps.validate_inputs.outputs.VERSION }} + release_id: ${{ steps.validate_inputs.outputs.RELEASE_ID }} + stable_tag: ${{ steps.validate_inputs.outputs.stable_tag }} steps: - name: Checkout sources @@ -105,15 +106,15 @@ jobs: echo "stable_tag=${STABLE_TAG}" >> $GITHUB_OUTPUT fetch-artifacts: # this job will be triggered for the polkadot-parachain rc and release or polkadot rc image build - if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} + if: ${{ inputs.binary == 'polkadot-omni-node' || inputs.binary == 'polkadot-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest - needs: [validate-inputs] + needs: [ validate-inputs ] steps: - name: Checkout sources uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - #TODO: this step will be needed when automated triggering will work + #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: | @@ -129,7 +130,7 @@ jobs: - 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 != '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 @@ -143,9 +144,9 @@ jobs: fetch_release_artifacts_from_s3 $BINARY fi - - name: Fetch chain-spec-builder rc artifacts or release artifacts based on release id + - 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 == '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 @@ -159,9 +160,9 @@ jobs: path: release-artifacts/${{ 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-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} + if: ${{ inputs.binary == 'polkadot-omni-node' || inputs.binary == 'polkadot-parachain' || inputs.binary == 'chain-spec-builder' || inputs.image_type == 'rc' }} runs-on: ubuntu-latest - needs: [fetch-artifacts, validate-inputs] + needs: [ fetch-artifacts, validate-inputs ] environment: release steps: @@ -194,14 +195,12 @@ jobs: run: | . ./.github/scripts/common/lib.sh - release="${{ needs.validate-inputs.outputs.stable_tag }}" && \ - echo "release=${release}" >> $GITHUB_OUTPUT + echo "release=${{ needs.validate-inputs.outputs.stable_tag }}" >> $GITHUB_OUTPUT commit=$(git rev-parse --short HEAD) && \ echo "commit=${commit}" >> $GITHUB_OUTPUT - tag="${{ needs.validate-inputs.outputs.version }}" && \ - echo "tag=${tag}" >> $GITHUB_OUTPUT + echo "tag=${{ needs.validate-inputs.outputs.version }}" >> $GITHUB_OUTPUT - name: Fetch release tags working-directory: release-artifacts @@ -233,8 +232,8 @@ jobs: echo "Building container for $BINARY" ./docker/scripts/polkadot/build-injected.sh $ARTIFACTS_FOLDER - - name: Build Injected Container image chain-spec-builder - if: ${{ env.BINARY == 'chain-spec-builder' }} + - name: Build Injected Container image for polkadot-omni-node/chain-spec-builder + if: ${{ env.BINARY == 'polkadot-omni-node' || env.BINARY == 'chain-spec-builder' }} env: ARTIFACTS_FOLDER: release-artifacts IMAGE_NAME: ${{ env.BINARY }} @@ -268,8 +267,8 @@ jobs: username: ${{ secrets.POLKADOT_DOCKERHUB_USERNAME }} password: ${{ secrets.POLKADOT_DOCKERHUB_TOKEN }} - - name: Login to Dockerhub to puiblish polkadot-parachain/chain-spec-builder - if: ${{ env.BINARY == 'polkadot-parachain' || env.BINARY == 'chain-spec-builder' }} + - name: Login to Dockerhub to publish polkadot-omni-node/polkadot-parachain/chain-spec-builder + if: ${{ env.BINARY == 'polkadot-omni-node' || env.BINARY == 'polkadot-parachain' || env.BINARY == 'chain-spec-builder' }} uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: username: ${{ secrets.CUMULUS_DOCKERHUB_USERNAME }} @@ -317,22 +316,22 @@ jobs: build-polkadot-release-container: # this job will be triggered for polkadot release build if: ${{ inputs.binary == 'polkadot' && inputs.image_type == 'release' }} runs-on: ubuntu-latest - needs: [fetch-latest-debian-package-version, validate-inputs] + needs: [ fetch-latest-debian-package-version, validate-inputs ] environment: release steps: - name: Checkout sources uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - name: Cache Docker layers uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- - name: Login to Docker Hub uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 @@ -348,7 +347,7 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@32945a339266b759abcbdc89316275140b0fc960 # v6.8.0 + uses: docker/build-push-action@5e99dacf67635c4f273e532b9266ddb609b3025a # v6.9.0 with: push: true file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile diff --git a/.github/workflows/release-branchoff-stable.yml b/.github/workflows/release-branchoff-stable.yml index c4c50f5398e8..adce1b261b71 100644 --- a/.github/workflows/release-branchoff-stable.yml +++ b/.github/workflows/release-branchoff-stable.yml @@ -9,15 +9,10 @@ on: type: string node_version: - description: Version of the polkadot node in the format vX.XX.X (e.g. 1.15.0) + description: Version of the polkadot node in the format X.XX.X (e.g. 1.15.0) required: true jobs: - # TODO: Activate this job when the pipeline is moved to the fork in the `paritytech-release` org - # check-workflow-can-run: - # uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@latest - - prepare-tooling: runs-on: ubuntu-latest outputs: @@ -40,13 +35,11 @@ jobs: echo "stable_version=${stable_version}" >> $GITHUB_OUTPUT create-stable-branch: - # needs: [check-workflow-can-run, prepare-tooling] needs: [prepare-tooling] - # if: needs. check-workflow-can-run.outputs.checks_passed == 'true' 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 }} @@ -59,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: | @@ -70,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: | @@ -85,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 @@ -100,6 +103,8 @@ jobs: # Set new version for polkadot-parachain binary to match the polkadot node binary # set_polkadot_parachain_binary_version $NODE_VERSION "cumulus/polkadot-parachain/Cargo.toml" - reorder_prdocs $NODE_VERSION + reorder_prdocs $STABLE_BRANCH_NAME + + gh auth setup-git git push origin "$STABLE_BRANCH_NAME" diff --git a/.github/workflows/release-build-rc.yml b/.github/workflows/release-build-rc.yml new file mode 100644 index 000000000000..94bacf320898 --- /dev/null +++ b/.github/workflows/release-build-rc.yml @@ -0,0 +1,82 @@ +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 }} + 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 }} + 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-reusable-rc-buid.yml b/.github/workflows/release-reusable-rc-buid.yml new file mode 100644 index 000000000000..d925839fb84a --- /dev/null +++ b/.github/workflows/release-reusable-rc-buid.yml @@ -0,0 +1,193 @@ +name: RC Build + +on: + workflow_call: + inputs: + binary: + description: Binary to be build for the release + required: true + default: polkadot + type: string + + package: + description: Package to be built, for now is either polkadot or polkadot-parachain-bin + required: true + type: string + + release_tag: + description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM + required: true + type: string + + secrets: + PGP_KMS_KEY: + required: true + PGP_KMS_HASH: + required: true + AWS_ACCESS_KEY_ID: + required: true + AWS_SECRET_ACCESS_KEY: + required: true + AWS_DEFAULT_REGION: + required: true + AWS_RELEASE_ACCESS_KEY_ID: + required: true + AWS_RELEASE_SECRET_ACCESS_KEY: + required: true + +permissions: + id-token: write + contents: read + attestations: write + +jobs: + + set-image: + # GitHub Actions allows using 'env' in a container context. + # However, env variables don't work for forks: https://github.com/orgs/community/discussions/44322 + # This workaround sets the container image for each job using 'set-image' job output. + runs-on: ubuntu-latest + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + + build-rc: + needs: [set-image] + runs-on: ubuntu-latest-m + environment: release + container: + image: ${{ needs.set-image.outputs.IMAGE }} + 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 }} + + 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@5a8f82fbb607ea102d8c178e761659de54c7af69" + which pgpkms + + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: ${{ inputs.release_tag }} + fetch-depth: 0 + + - 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-linux-release.sh ${{ matrix.binaries }} ${{ inputs.package }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + with: + subject-path: /artifacts/${{ matrix.binaries }}/${{ matrix.binaries }} + + - name: Sign artifacts + working-directory: /artifacts/${{ matrix.binaries }} + run: | + python3 -m pgpkms sign --input ${{matrix.binaries }} -o ${{ matrix.binaries }}.asc + + - name: Check sha256 ${{ matrix.binaries }} + working-directory: /artifacts/${{ matrix.binaries }} + 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: /artifacts/${{ matrix.binaries }} + 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 }} + path: /artifacts/${{ matrix.binaries }} + + build-polkadot-deb-package: + if: ${{ inputs.package == 'polkadot' }} + needs: [build-rc] + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: ${{ inputs.release_tag }} + fetch-depth: 0 + + - name: Download artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + path: target/production + merge-multiple: true + + - name: Build polkadot deb package + shell: bash + run: | + . "${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 + with: + subject-path: target/production/*.deb + + - name: Upload ${{inputs.package }} artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: ${{ inputs.package }} + path: target/production + overwrite: true + + upload-polkadot-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot' }} + needs: [build-polkadot-deb-package] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + 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' }} + needs: [build-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: polkadot-parachain + release_tag: ${{ inputs.release_tag }} + 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-reusable-s3-upload.yml b/.github/workflows/release-reusable-s3-upload.yml new file mode 100644 index 000000000000..6776b78da8e6 --- /dev/null +++ b/.github/workflows/release-reusable-s3-upload.yml @@ -0,0 +1,53 @@ +name: Upload to s3 + +on: + workflow_call: + inputs: + package: + description: Package to be built, for now is either polkadot or polkadot-parachain-bin + required: true + type: string + + release_tag: + description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM-rcX + 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: + upload-artifacts-to-s3: + runs-on: ubuntu-latest + environment: release + 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 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Download artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: ${{ inputs.package }} + path: artifacts/${{ inputs.package }} + + - 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 }} artifacts to s3 + run: | + . ./.github/scripts/release/release_lib.sh + upload_s3_release ${{ inputs.package }} ${{ inputs.release_tag }} diff --git a/.github/workflows/release-srtool.yml b/.github/workflows/release-srtool.yml index 83119dd4ed24..9a29b46d2fc3 100644 --- a/.github/workflows/release-srtool.yml +++ b/.github/workflows/release-srtool.yml @@ -39,7 +39,8 @@ jobs: sudo dpkg -i toml.deb toml --version; jq --version - - name: Scan runtimes + - name: Scan and get runtimes list + id: get_runtimes_list env: EXCLUDED_RUNTIMES: ${{ inputs.excluded_runtimes }}:"substrate-test" run: | @@ -51,13 +52,6 @@ jobs: MATRIX=$(find_runtimes | tee runtimes_list.json) echo $MATRIX - - - name: Get runtimes list - id: get_runtimes_list - run: | - ls -al - MATRIX=$(cat runtimes_list.json) - echo $MATRIX echo "runtime=$MATRIX" >> $GITHUB_OUTPUT srtool: diff --git a/.github/workflows/runtimes-matrix.json b/.github/workflows/runtimes-matrix.json index 50fa44b1b073..f991db55b86d 100644 --- a/.github/workflows/runtimes-matrix.json +++ b/.github/workflows/runtimes-matrix.json @@ -5,7 +5,8 @@ "path": "substrate/frame", "header": "substrate/HEADER-APACHE2", "template": "substrate/.maintain/frame-weight-template.hbs", - "bench_features": "runtime-benchmarks,riscv", + "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, "is_relay": false }, @@ -15,8 +16,9 @@ "path": "polkadot/runtime/westend", "header": "polkadot/file_header.txt", "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", - "uri": "wss://try-runtime-westend.polkadot.io:443", + "bench_flags": "", "bench_features": "runtime-benchmarks", + "uri": "wss://try-runtime-westend.polkadot.io:443", "is_relay": true }, { @@ -27,6 +29,7 @@ "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", "uri": "wss://try-runtime-rococo.polkadot.io:443", "bench_features": "runtime-benchmarks", + "bench_flags": "", "is_relay": true }, { @@ -36,6 +39,7 @@ "header": "cumulus/file_header.txt", "template": "cumulus/templates/xcm-bench-template.hbs", "bench_features": "runtime-benchmarks", + "bench_flags": "", "uri": "wss://westend-asset-hub-rpc.polkadot.io:443", "is_relay": false }, @@ -44,8 +48,9 @@ "package": "asset-hub-rococo-runtime", "path": "cumulus/parachains/runtimes/assets/asset-hub-rococo", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", "uri": "wss://rococo-asset-hub-rpc.polkadot.io:443", "is_relay": false }, @@ -54,8 +59,9 @@ "package": "bridge-hub-rococo-runtime", "path": "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", "uri": "wss://rococo-bridge-hub-rpc.polkadot.io:443", "is_relay": false }, @@ -64,8 +70,9 @@ "package": "bridge-hub-rococo-runtime", "path": "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", "uri": "wss://westend-bridge-hub-rpc.polkadot.io:443", "is_relay": false }, @@ -74,8 +81,9 @@ "package": "collectives-westend-runtime", "path": "cumulus/parachains/runtimes/collectives/collectives-westend", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", "uri": "wss://westend-collectives-rpc.polkadot.io:443" }, { @@ -83,8 +91,9 @@ "package": "contracts-rococo-runtime", "path": "cumulus/parachains/runtimes/contracts/contracts-rococo", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm", "uri": "wss://rococo-contracts-rpc.polkadot.io:443", "is_relay": false }, @@ -93,8 +102,9 @@ "package": "coretime-rococo-runtime", "path": "cumulus/parachains/runtimes/coretime/coretime-rococo", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "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", "is_relay": false }, @@ -103,8 +113,9 @@ "package": "coretime-westend-runtime", "path": "cumulus/parachains/runtimes/coretime/coretime-westend", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "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", "is_relay": false }, @@ -113,8 +124,9 @@ "package": "glutton-westend-runtime", "path": "cumulus/parachains/runtimes/gluttons/glutton-westend", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none", "uri": null, "is_relay": false }, @@ -123,8 +135,9 @@ "package": "people-rococo-runtime", "path": "cumulus/parachains/runtimes/people/people-rococo", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "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", "is_relay": false }, @@ -133,8 +146,9 @@ "package": "people-westend-runtime", "path": "cumulus/parachains/runtimes/people/people-westend", "header": "cumulus/file_header.txt", - "bench_features": "runtime-benchmarks", "template": "cumulus/templates/xcm-bench-template.hbs", + "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", "is_relay": false } diff --git a/.github/workflows/tests-linux-stable-coverage.yml b/.github/workflows/tests-linux-stable-coverage.yml index 90d7bc34a926..c5af6bcae77f 100644 --- a/.github/workflows/tests-linux-stable-coverage.yml +++ b/.github/workflows/tests-linux-stable-coverage.yml @@ -56,7 +56,7 @@ jobs: --no-report --release --workspace --locked --no-fail-fast - --features try-runtime,ci-only-tests,experimental,riscv + --features try-runtime,ci-only-tests,experimental --filter-expr " !test(/.*benchmark.*/) - test(/recovers_from_only_chunks_if_pov_large::case_1/) @@ -120,4 +120,4 @@ jobs: - uses: actions/checkout@v4 - uses: actions-ecosystem/action-remove-labels@v1 with: - labels: GHA-coverage \ No newline at end of file + labels: GHA-coverage diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml index 599edd8e69a1..b9d0605b2495 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' }} + 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' }} + 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 '*' @@ -91,12 +106,60 @@ jobs: --release \ --no-fail-fast \ --cargo-quiet \ - --features try-runtime,experimental,riscv,ci-only-tests \ + --features try-runtime,experimental,ci-only-tests \ --partition count:${{ matrix.partition }} # run runtime-api tests with `enable-staging-api` feature on the 1st node - name: runtime-api tests if: ${{ matrix.partition == '1/3' }} run: forklift cargo nextest run -p sp-api-test --features enable-staging-api --cargo-quiet + - name: Stop all workflows if failed + if: ${{ failure() && steps.required.conclusion == 'failure' }} + 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 + # + # all_security_features_work and nonexistent_cache_dir are currently skipped + # becuase runners don't have the necessary permissions to run them + test-linux-stable-no-try-runtime: + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + strategy: + fail-fast: false + matrix: + partition: [1/2, 2/2] + env: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + id: required + run: | + forklift cargo nextest run --workspace \ + --locked \ + --release \ + --no-fail-fast \ + --cargo-quiet \ + --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' }} + 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 @@ -107,6 +170,7 @@ jobs: test-linux-stable-int, test-linux-stable-runtime-benchmarks, test-linux-stable, + test-linux-stable-no-try-runtime, ] if: always() && !cancelled() steps: diff --git a/.github/workflows/tests-misc.yml b/.github/workflows/tests-misc.yml index 45ed4ebdc6cb..cca32650b106 100644 --- a/.github/workflows/tests-misc.yml +++ b/.github/workflows/tests-misc.yml @@ -157,7 +157,6 @@ jobs: node-bench-regression-guard: timeout-minutes: 20 if: always() && !cancelled() - # runs-on: arc-runners-polkadot-sdk runs-on: ubuntu-latest needs: [preflight, cargo-check-benches] steps: @@ -179,6 +178,11 @@ jobs: - name: script id: compare run: | + if [ "${{ github.ref_name }}" = "master" ]; then + echo -e "Exiting on master branch" + exit 0 + fi + docker run --rm \ -v $PWD/artifacts/master:/artifacts/master \ -v $PWD/artifacts/current:/artifacts/current \ @@ -300,7 +304,7 @@ jobs: # name: hfuzz-${{ github.sha }} cargo-check-each-crate: - timeout-minutes: 140 + timeout-minutes: 70 needs: [preflight] runs-on: ${{ needs.preflight.outputs.RUNNER }} if: ${{ needs.preflight.outputs.changes_rust }} @@ -344,7 +348,7 @@ jobs: - name: Set up Homebrew uses: Homebrew/actions/setup-homebrew@1ccc07ccd54b6048295516a3eb89b192c35057dc # master from 12.09.2024 - name: Install rust ${{ env.RUST_VERSION }} - uses: actions-rust-lang/setup-rust-toolchain@4d1965c9142484e48d40c19de54b5cba84953a06 # v1.10.0 + uses: actions-rust-lang/setup-rust-toolchain@11df97af8e8102fd60b60a77dfbf58d40cd843b8 # v1.10.1 with: cache: false toolchain: ${{ env.RUST_VERSION }} diff --git a/.gitignore b/.gitignore index 0263626d832d..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 @@ -40,3 +39,5 @@ rls*.log runtime/wasm/target/ substrate.code-workspace target/ +*.scale +justfile diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dbc5dafeb0ae..f508404f1efa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -225,8 +225,6 @@ include: - .gitlab/pipeline/test.yml # build jobs - .gitlab/pipeline/build.yml - # short-benchmarks jobs - - .gitlab/pipeline/short-benchmarks.yml # publish jobs - .gitlab/pipeline/publish.yml # zombienet jobs @@ -284,8 +282,3 @@ cancel-pipeline-build-linux-substrate: extends: .cancel-pipeline-template needs: - job: build-linux-substrate - -cancel-pipeline-build-short-benchmark: - extends: .cancel-pipeline-template - needs: - - job: build-short-benchmark diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 0d509879b449..1bd04ae670f4 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -100,49 +100,6 @@ build-templates-node: - mv ./target/release/minimal-template-node ./artifacts/. - mv ./target/release/solochain-template-node ./artifacts/. -build-rustdoc: - stage: build - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - 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" - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - when: on_success - expire_in: 1 days - paths: - - ./crate-docs/ - script: - - time cargo doc --all-features --workspace --no-deps - - rm -f ./target/doc/.lock - - mv ./target/doc ./crate-docs - # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into - # all .html files - - > - inject_simple_analytics() { - local path="$1"; - local script_content=""; - - # Function that inject script into the head of an html file using sed. - process_file() { - local file="$1"; - echo "Adding Simple Analytics script to $file"; - sed -i "s||$script_content|" "$file"; - }; - export -f process_file; - # xargs runs process_file in separate shells without access to outer variables. - # make script_content available inside process_file, export it as an env var here. - export script_content; - - # Modify .html files in parallel using xargs, otherwise it can take a long time. - find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {}; - }; - inject_simple_analytics "./crate-docs"; - - echo "" > ./crate-docs/index.html - build-implementers-guide: stage: build extends: @@ -160,19 +117,6 @@ build-implementers-guide: - mkdir -p artifacts - mv polkadot/roadmap/implementers-guide/book artifacts/ -build-short-benchmark: - stage: build - extends: - - .docker-env - - .common-refs - - .run-immediately - - .collect-artifacts - script: - - cargo build --profile release --locked --features=runtime-benchmarks,on-chain-release-build --bin polkadot --workspace - - mkdir -p artifacts - - target/release/polkadot --version - - cp ./target/release/polkadot ./artifacts/ - build-polkadot-zombienet-tests: stage: build extends: @@ -191,7 +135,6 @@ build-polkadot-zombienet-tests: - mkdir -p artifacts - cp polkadot-zombienet-tests.tar.zst ./artifacts - # build jobs from cumulus build-linux-stable-cumulus: @@ -234,92 +177,6 @@ build-test-parachain: - mkdir -p ./artifacts/zombienet - mv ./target/release/wbuild/cumulus-test-runtime/wasm_binary_spec_version_incremented.rs.compact.compressed.wasm ./artifacts/zombienet/. -# build runtime only if files in $RUNTIME_PATH/$RUNTIME_NAME were changed -.build-runtime-template: &build-runtime-template - stage: build - extends: - - .docker-env - - .test-refs-no-trigger-prs-only - - .run-immediately - variables: - RUNTIME_PATH: "parachains/runtimes/assets" - script: - - cd ${RUNTIME_PATH} - - for directory in $(echo */); do - echo "_____Running cargo check for ${directory} ______"; - cd ${directory}; - pwd; - SKIP_WASM_BUILD=1 cargo check --locked; - cd ..; - done - -# DAG: build-runtime-assets -> build-runtime-collectives -> build-runtime-bridge-hubs -# DAG: build-runtime-assets -> build-runtime-collectives -> build-runtime-contracts -# DAG: build-runtime-assets -> build-runtime-coretime -# DAG: build-runtime-assets -> build-runtime-testing -build-runtime-assets: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/assets" - -build-runtime-collectives: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/collectives" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-coretime: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/coretime" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-bridge-hubs: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/bridge-hubs" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-collectives - artifacts: false - -build-runtime-contracts: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/contracts" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-collectives - artifacts: false - -build-runtime-testing: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/testing" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-short-benchmark-cumulus: - stage: build - extends: - - .docker-env - - .common-refs - - .run-immediately - - .collect-artifacts - script: - - cargo build --profile release --locked --features=runtime-benchmarks,on-chain-release-build -p polkadot-parachain-bin --bin polkadot-parachain --workspace - - mkdir -p artifacts - - target/release/polkadot-parachain --version - - cp ./target/release/polkadot-parachain ./artifacts/ - # substrate build-linux-substrate: @@ -340,7 +197,7 @@ build-linux-substrate: # tldr: we need to checkout the branch HEAD explicitly because of our dynamic versioning approach while building the substrate binary # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 - git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA" - - !reference [ .forklift-cache, before_script ] + - !reference [.forklift-cache, before_script] script: - time WASM_BUILD_NO_COLOR=1 cargo build --locked --release -p staging-node-cli - mv $CARGO_TARGET_DIR/release/substrate-node ./artifacts/substrate/substrate diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index c0ce058f17ff..92deaea2f612 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -1,67 +1,6 @@ # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "publish" stage -publish-rustdoc: - stage: publish - extends: - - .kubernetes-env - - .publish-gh-pages-refs - variables: - CI_IMAGE: node:18 - GIT_DEPTH: 100 - RUSTDOCS_DEPLOY_REFS: "master" - needs: - - job: build-rustdoc - artifacts: true - - job: build-implementers-guide - artifacts: true - script: - # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we - # exit immediately. - # Putting spaces at the front and back to ensure we are not matching just any substring, but the - # whole space-separated value. - # setup ssh - - eval $(ssh-agent) - - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - - mkdir ~/.ssh && touch ~/.ssh/known_hosts - - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - # Set git config - - git config user.email "devops-team@parity.io" - - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - - git fetch origin gh-pages - # Save README and docs - - cp -r ./crate-docs/ /tmp/doc/ - - cp -r ./artifacts/book/ /tmp/ - - cp README.md /tmp/doc/ - # we don't need to commit changes because we copy docs to /tmp - - git checkout gh-pages --force - # Enable if docs needed for other refs - # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - # - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - # - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} - # Ensure the destination dir doesn't exist. - - rm -rf ${CI_COMMIT_REF_NAME} - - rm -rf book/ - - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} - # dir for implementors guide - - mkdir -p book - - mv /tmp/book/html/* book/ - # Upload files - - git add --all - # `git commit` has an exit code of > 0 if there is nothing to commit. - # This causes GitLab to exit immediately and marks this job failed. - # We don't want to mark the entire job failed if there's nothing to - # publish though, hence the `|| true`. - - git commit --amend -m "___Updated docs" || - echo "___Nothing to commit___" - - git push origin gh-pages --force - # artificial sleep to publish gh-pages - - sleep 300 - after_script: - - rm -rf .git/ ./* - # note: images are used not only in zombienet but also in rococo, wococo and versi .build-push-image: image: $BUILDAH_IMAGE diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index ad09f3f7cb0a..ed97d539c095 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -1,121 +1 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "short-benchmarks" stage - -# Run all pallet benchmarks only once to check if there are any errors - -# run short-benchmarks for relay chain runtimes from polkadot - -short-benchmark-westend: &short-bench - stage: short-benchmarks - extends: - - .docker-env - - .common-refs - needs: - - job: build-short-benchmark - artifacts: true - variables: - RUNTIME: westend - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - tags: - - benchmark - script: - - ./artifacts/polkadot benchmark pallet --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - -short-benchmark-rococo: &short-bench - stage: short-benchmarks - extends: - - .docker-env - - .common-refs - needs: - - job: build-short-benchmark - artifacts: true - variables: - RUNTIME: rococo - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - tags: - - benchmark - script: - - ./artifacts/polkadot benchmark pallet --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - -# run short-benchmarks for system parachain runtimes from cumulus - -.short-benchmark-cumulus: &short-bench-cumulus - stage: short-benchmarks - extends: - - .common-refs - - .docker-env - needs: - - job: build-short-benchmark-cumulus - artifacts: true - variables: - RUNTIME_CHAIN: benchmarked-runtime-chain - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - tags: - - benchmark - script: - - ./artifacts/polkadot-parachain benchmark pallet --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - -short-benchmark-asset-hub-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: asset-hub-rococo-dev - -short-benchmark-asset-hub-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: asset-hub-westend-dev - -short-benchmark-bridge-hub-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: bridge-hub-rococo-dev - -short-benchmark-bridge-hub-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: bridge-hub-westend-dev - -short-benchmark-collectives-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: collectives-westend-dev - -short-benchmark-coretime-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: coretime-rococo-dev - -short-benchmark-coretime-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: coretime-westend-dev - -short-benchmark-people-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: people-rococo-dev - -short-benchmark-people-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: people-westend-dev - -short-benchmark-glutton-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: glutton-westend-dev-1300 +--- diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 0252620cd0f3..8e32a3614679 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -109,72 +109,3 @@ test-linux-stable-codecov: else codecovcli -v do-upload -f target/coverage/result/report-${CI_NODE_INDEX}.lcov --disable-search -t ${CODECOV_TOKEN} -r paritytech/polkadot-sdk --commit-sha ${CI_COMMIT_SHA} --fail-on-error --git-service github; fi - -# some tests do not run with `try-runtime` feature enabled -# https://github.com/paritytech/polkadot-sdk/pull/4251#discussion_r1624282143 -# Move to github after https://github.com/paritytech/ci_cd/issues/1056 is fixed -test-linux-stable-no-try-runtime: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - variables: - RUST_TOOLCHAIN: stable - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - > - time cargo nextest run \ - --workspace \ - --locked \ - --release \ - --no-fail-fast \ - --cargo-quiet \ - --features experimental,riscv,ci-only-tests - -test-doc: - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: test-rustdoc - artifacts: false - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - time cargo test --doc --workspace - -test-rustdoc: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - SKIP_WASM_BUILD: 1 - script: - - time cargo doc --workspace --all-features --no-deps - -quick-benchmarks-omni: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions" - script: - - time cargo build --locked --quiet --release -p asset-hub-westend-runtime --features runtime-benchmarks - - time 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 diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index b02d857f3f24..08bfed2e24ce 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,12 +1,14 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.113" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.116" PUSHGATEWAY_URL: "http://zombienet-prometheus-pushgateway.managed-monitoring:9091/metrics/job/zombie-metrics" DEBUG: "zombie,zombie::network-node,zombie::kube::client::logs" ZOMBIE_PROVIDER: "k8s" RUST_LOG: "info,zombienet_orchestrator=debug" RUN_IN_CI: "1" + KUBERNETES_CPU_REQUEST: "512m" + KUBERNETES_MEMORY_REQUEST: "1Gi" timeout: 60m include: diff --git a/.gitlab/pipeline/zombienet/bridges.yml b/.gitlab/pipeline/zombienet/bridges.yml index 070bfc8472d5..07711e32a9a3 100644 --- a/.gitlab/pipeline/zombienet/bridges.yml +++ b/.gitlab/pipeline/zombienet/bridges.yml @@ -11,7 +11,7 @@ - if: $CI_COMMIT_REF_NAME =~ /^gh-readonly-queue.*$/ variables: DOCKER_IMAGES_VERSION: ${CI_COMMIT_SHORT_SHA} - - !reference [.build-refs, rules] + - !reference [ .build-refs, rules ] before_script: - echo "Zombienet Tests Config" - echo "${ZOMBIENET_IMAGE}" diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 0da95f224cfc..3dab49a118e5 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -158,7 +158,7 @@ zombienet-polkadot-functional-0010-validator-disabling: --local-dir="${LOCAL_DIR}/functional" --test="0010-validator-disabling.zndsl" -zombienet-polkadot-functional-0011-async-backing-6-seconds-rate: +.zombienet-polkadot-functional-0011-async-backing-6-seconds-rate: extends: - .zombienet-polkadot-common script: @@ -172,7 +172,7 @@ zombienet-polkadot-elastic-scaling-0001-basic-3cores-6s-blocks: variables: FORCED_INFRA_INSTANCE: "spot-iops" before_script: - - !reference [.zombienet-polkadot-common, before_script] + - !reference [ .zombienet-polkadot-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/elastic_scaling script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh @@ -183,14 +183,14 @@ zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains: extends: - .zombienet-polkadot-common before_script: - - !reference [.zombienet-polkadot-common, before_script] + - !reference [ .zombienet-polkadot-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/elastic_scaling script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/elastic_scaling" --test="0002-elastic-scaling-doesnt-break-parachains.zndsl" -zombienet-polkadot-functional-0012-spam-statement-distribution-requests: +.zombienet-polkadot-functional-0012-spam-statement-distribution-requests: extends: - .zombienet-polkadot-common script: @@ -218,14 +218,14 @@ zombienet-polkadot-functional-0015-coretime-shared-core: extends: - .zombienet-polkadot-common before_script: - - !reference [.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="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,6 +233,25 @@ zombienet-polkadot-functional-0016-approval-voting-parallel: --local-dir="${LOCAL_DIR}/functional" --test="0016-approval-voting-parallel.zndsl" +zombienet-polkadot-functional-0017-sync-backing: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0017-sync-backing.zndsl" + +zombienet-polkadot-functional-0018-shared-core-idle-parachain: + 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="0018-shared-core-idle-parachain.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common @@ -277,7 +296,7 @@ zombienet-polkadot-smoke-0002-parachains-parachains-upgrade-smoke: --local-dir="${LOCAL_DIR}/smoke" --test="0002-parachains-upgrade-smoke-test.zndsl" -zombienet-polkadot-smoke-0003-deregister-register-validator: +.zombienet-polkadot-smoke-0003-deregister-register-validator: extends: - .zombienet-polkadot-common script: @@ -360,10 +379,10 @@ zombienet-polkadot-malus-0001-dispute-valid: - job: build-polkadot-zombienet-tests artifacts: true before_script: - - !reference [".zombienet-polkadot-common", "before_script"] + - !reference [ ".zombienet-polkadot-common", "before_script" ] - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}" script: - # we want to use `--no-capture` in zombienet tests. + # 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 -- smoke::coretime_revenue::coretime_revenue_test diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index d4ffa34f3395..52118307e6a0 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -74,7 +74,7 @@ zombienet-substrate-0002-validators-warp-sync: extends: - .zombienet-substrate-warp-sync-common before_script: - - !reference [.zombienet-substrate-warp-sync-common, before_script] + - !reference [ .zombienet-substrate-warp-sync-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/0001-basic-warp-sync/chain-spec.json ${LOCAL_DIR}/0002-validators-warp-sync script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh @@ -85,7 +85,7 @@ zombienet-substrate-0003-block-building-warp-sync: extends: - .zombienet-substrate-warp-sync-common before_script: - - !reference [.zombienet-substrate-warp-sync-common, before_script] + - !reference [ .zombienet-substrate-warp-sync-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/0001-basic-warp-sync/chain-spec.json ${LOCAL_DIR}/0003-block-building-warp-sync script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh diff --git a/Cargo.lock b/Cargo.lock index d2acd35e9323..bdc24163737f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,7 +135,7 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more", + "derive_more 0.99.17", "hex-literal", "itoa", "proptest", @@ -168,7 +168,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "syn-solidity", "tiny-keccak", ] @@ -295,7 +295,7 @@ dependencies = [ "proc-macro-error", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -753,7 +753,7 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "synstructure 0.13.1", ] @@ -776,7 +776,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -806,14 +806,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", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] @@ -821,110 +822,112 @@ 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", - "primitive-types", - "rococo-runtime-constants", + "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", + "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-runtime-common 7.0.0", + "primitive-types 0.13.1", + "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-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]] @@ -933,13 +936,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", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", "westend-emulated-chain", ] @@ -948,167 +952,224 @@ 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-keyring", - "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-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", - "primitive-types", + "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", + "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-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-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", +] + +[[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]] @@ -1139,7 +1200,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", @@ -1230,7 +1291,7 @@ dependencies = [ "futures-lite 2.3.0", "parking", "polling 3.4.0", - "rustix 0.38.21", + "rustix 0.38.25", "slab", "tracing", "windows-sys 0.52.0", @@ -1251,7 +1312,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", ] @@ -1310,9 +1371,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.21", + "rustix 0.38.25", "tracing", ] @@ -1328,7 +1389,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.21", + "rustix 0.38.25", "signal-hook-registry", "slab", "windows-sys 0.52.0", @@ -1380,7 +1441,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1391,13 +1452,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.79", + "syn 2.0.87", ] [[package]] @@ -1563,15 +1624,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" @@ -1585,6 +1637,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" @@ -1612,16 +1674,32 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "bip32" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +dependencies = [ + "bs58", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.8", + "subtle 2.5.0", + "zeroize", ] [[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", ] @@ -1648,10 +1726,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" @@ -1660,7 +1738,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]] @@ -1765,9 +1853,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec 0.7.4", @@ -1818,9 +1906,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", @@ -1842,8 +1930,8 @@ 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", ] @@ -1852,8 +1940,8 @@ dependencies = [ 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", ] @@ -1862,15 +1950,15 @@ dependencies = [ 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", ] @@ -1879,12 +1967,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", ] @@ -1894,9 +1982,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", @@ -1907,9 +1995,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", @@ -1920,10 +2008,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", @@ -1935,10 +2023,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", @@ -1949,29 +2037,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", ] @@ -1980,9 +2086,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", @@ -1993,14 +2099,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", @@ -2009,28 +2132,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", @@ -2042,13 +2197,12 @@ 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", - "parity-util-mem", "scale-info", "serde", "sp-core 28.0.0", @@ -2056,33 +2210,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", ] @@ -2091,8 +2283,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", @@ -2107,36 +2299,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-runtime" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "746d9464f912b278f8a5e2400f10541f95da7fc6c7d688a2788b9a46296146ee" +dependencies = [ + "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", - "bp-parachains", - "bp-polkadot-core", - "bp-runtime", + "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", + "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", ] @@ -2145,16 +2382,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]] @@ -2165,70 +2420,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", - "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", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -2240,153 +2528,198 @@ 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", + "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", + "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", - "staging-xcm", - "testnet-parachains-constants", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", + "testnet-parachains-constants 1.0.0", ] [[package]] @@ -2395,33 +2728,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", + "staging-xcm 7.0.0", + "staging-xcm-executor 7.0.0", + "testnet-parachains-constants 1.0.0", + "xcm-runtime-apis 0.1.0", ] [[package]] @@ -2432,119 +2766,119 @@ 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", + "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", + "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", @@ -2552,17 +2886,51 @@ dependencies = [ "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-trie 29.0.0", - "staging-xcm", + "sp-weights 27.0.0", + "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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ + "sha2 0.10.8", "tinyvec", ] @@ -2708,12 +3076,13 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.94" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -2752,12 +3121,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chacha" version = "0.3.0" @@ -2797,24 +3160,25 @@ name = "chain-spec-guide-runtime" version = "0.0.0" dependencies = [ "docify", - "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]] @@ -3031,7 +3395,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3049,6 +3413,32 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +[[package]] +name = "cmd_lib" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "371c15a3c178d0117091bd84414545309ca979555b1aad573ef591ad58818d41" +dependencies = [ + "cmd_lib_macros", + "env_logger 0.10.1", + "faccess", + "lazy_static", + "log", + "os_pipe", +] + +[[package]] +name = "cmd_lib_macros" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb844bd05be34d91eb67101329aeba9d3337094c04fd8507d821db7ebb488eaf" +dependencies = [ + "proc-macro-error2", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "coarsetime" version = "0.1.23" @@ -3076,12 +3466,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]] @@ -3089,26 +3479,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", ] @@ -3116,78 +3506,79 @@ 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", + "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-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]] @@ -3322,9 +3713,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", ] @@ -3421,64 +3812,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]] @@ -3532,99 +3923,99 @@ 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", + "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]] @@ -3632,31 +4023,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", ] @@ -3664,66 +4055,66 @@ 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", + "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]] @@ -3934,22 +4325,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" @@ -4000,6 +4387,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" @@ -4032,9 +4434,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", @@ -4043,7 +4445,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", @@ -4064,8 +4466,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", @@ -4074,7 +4476,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", @@ -4085,16 +4487,16 @@ 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", "substrate-prometheus-endpoint", "tokio", "tracing", @@ -4106,26 +4508,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", @@ -4139,9 +4541,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", @@ -4153,17 +4555,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", @@ -4174,7 +4576,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", @@ -4184,8 +4586,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", @@ -4195,7 +4597,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", @@ -4211,15 +4613,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", @@ -4233,7 +4635,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", @@ -4243,7 +4645,7 @@ dependencies = [ "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-overseer", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "portpicker", "rand", "rstest", @@ -4272,13 +4674,13 @@ 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", + "polkadot-primitives 7.0.0", "sc-client-api", "sc-consensus", "sc-network", @@ -4296,41 +4698,77 @@ 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-dmp-queue" -version = "0.7.0" +name = "cumulus-pallet-aura-ext" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cbe2735fc7cf2b6521eab00cb1a1ab025abc1575cc36887b36dc8c5cb1c9434" dependencies = [ - "cumulus-primitives-core", - "frame-benchmarking", - "frame-support", - "frame-system", - "log", + "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-core 28.0.0", + "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 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-core 28.0.0", "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]] @@ -4339,96 +4777,191 @@ 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-common 7.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.79", + "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]] @@ -4436,39 +4969,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]] @@ -4479,8 +5054,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", @@ -4494,7 +5069,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]] @@ -4502,14 +5091,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]] @@ -4517,14 +5123,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" @@ -4537,16 +5158,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-support", - "frame-system", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -4555,29 +5188,75 @@ 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-primitives-utility" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bdcf4d46dd93f1e6d5dd6d379133566a44042ba6476d04bdcbdb4981c622ae4" +dependencies = [ + "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]] @@ -4585,13 +5264,13 @@ name = "cumulus-relay-chain-inprocess-interface" version = "0.7.0" dependencies = [ "async-trait", - "cumulus-primitives-core", + "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", @@ -4603,7 +5282,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", ] @@ -4613,9 +5292,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", @@ -4632,16 +5311,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", @@ -4653,7 +5332,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", @@ -4665,12 +5344,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", @@ -4686,8 +5365,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", @@ -4705,19 +5384,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", @@ -4727,14 +5406,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", ] @@ -4742,53 +5421,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-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]] @@ -4807,27 +5502,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", @@ -4853,16 +5548,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 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", @@ -4940,7 +5636,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4980,7 +5676,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "scratch", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4997,17 +5693,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", -] - -[[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]] @@ -5016,22 +5702,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]] @@ -5045,18 +5717,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.79", -] - -[[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]] @@ -5065,9 +5726,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.79", + "syn 2.0.87", ] [[package]] @@ -5184,7 +5845,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5195,7 +5856,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5206,7 +5867,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5222,6 +5883,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" @@ -5314,7 +5996,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5356,18 +6038,18 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce" +checksum = "a772b62b1837c8f060432ddcc10b17aae1453ef17617a99bc07789252d2a5896" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad" +checksum = "60e6be249b0a462a14784a99b19bf35a667bb5e09de611738bb7362fa4c95ff7" dependencies = [ "common-path", "derive-syn-parse", @@ -5375,7 +6057,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "regex", - "syn 2.0.79", + "syn 2.0.87", "termcolor", "toml 0.8.12", "walkdir", @@ -5540,33 +6222,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 31.0.0", "sp-runtime 31.0.1", - "staging-xcm", + "staging-xcm 7.0.0", "xcm-emulator", ] @@ -5606,7 +6289,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5626,7 +6309,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5637,7 +6320,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5704,9 +6387,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", @@ -5729,7 +6412,7 @@ dependencies = [ "honggfuzz", "polkadot-erasure-coding", "polkadot-node-primitives", - "polkadot-primitives", + "polkadot-primitives 7.0.0", ] [[package]] @@ -5753,13 +6436,40 @@ 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.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d398648d65820a727d6a81e58b962f874473396a047e4c30bafe3240953417" dependencies = [ - "ethereum-types", + "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", ] @@ -5771,9 +6481,24 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", + "impl-codec 0.6.0", + "impl-rlp 0.3.0", + "impl-serde 0.4.0", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c321610643004cf908ec0f5f2aa0d8f1f8e14b540562a2887a1111ff1ecbf7b" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec 0.7.0", + "impl-rlp 0.4.0", + "impl-serde 0.5.0", "scale-info", "tiny-keccak", ] @@ -5784,37 +6509,43 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ - "ethbloom", + "ethbloom 0.13.0", "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", + "impl-codec 0.6.0", + "impl-rlp 0.3.0", + "impl-serde 0.4.0", + "primitive-types 0.12.2", "scale-info", - "uint", + "uint 0.9.5", ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "ethereum-types" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "1ab15ed80916029f878e0267c3a9f92b67df55e79af370bf66199059ae2b4ee3" +dependencies = [ + "ethbloom 0.14.1", + "fixed-hash", + "impl-codec 0.7.0", + "impl-rlp 0.4.0", + "impl-serde 0.5.0", + "primitive-types 0.13.1", + "scale-info", + "uint 0.10.0", +] [[package]] name = "event-listener" -version = "4.0.3" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "pin-project-lite", -] +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[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", @@ -5827,7 +6558,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", ] @@ -5852,7 +6583,7 @@ dependencies = [ "prettyplease", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5866,8 +6597,19 @@ dependencies = [ ] [[package]] -name = "fallible-iterator" -version = "0.2.0" +name = "faccess" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5" +dependencies = [ + "bitflags 1.3.2", + "libc", + "winapi", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" @@ -5924,7 +6666,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -6038,7 +6780,7 @@ dependencies = [ "async-std", "async-trait", "backoff", - "bp-header-chain", + "bp-header-chain 0.7.0", "futures", "log", "num-traits", @@ -6173,27 +6915,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" @@ -6203,15 +6973,21 @@ dependencies = [ "chrono", "clap 4.5.13", "comfy-table", - "frame-benchmarking", - "frame-support", - "frame-system", + "cumulus-client-parachain-inherent", + "cumulus-primitives-proof-size-hostfunction 0.2.0", + "cumulus-test-runtime", + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", "gethostname", "handlebars", + "hex", "itertools 0.11.0", "linked-hash-map", "log", "parity-scale-codec", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "rand", "rand_pcg", "sc-block-builder", @@ -6220,88 +6996,156 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-executor 0.32.0", + "sc-executor-common 0.29.0", "sc-service", "sc-sysinfo", "serde", "serde_json", "sp-api 26.0.0", + "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 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", + "substrate-test-runtime", + "subxt", + "subxt-signer", "thiserror", "thousands", + "westend-runtime", ] [[package]] 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.79", + "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", ] @@ -6311,16 +7155,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", @@ -6328,14 +7172,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]] @@ -6350,15 +7202,28 @@ 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-hash-extension" version = "0.1.0" dependencies = [ "array-bytes", + "const-hex", "docify", "frame-metadata 16.0.0", - "frame-support", - "frame-system", + "frame-support 28.0.0", + "frame-system 28.0.0", "log", "merkleized-metadata", "parity-scale-codec", @@ -6366,22 +7231,44 @@ 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]] name = "frame-omni-bencher" 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 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", ] @@ -6391,7 +7278,7 @@ version = "0.35.0" dependencies = [ "futures", "indicatif", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "serde", @@ -6411,16 +7298,17 @@ dependencies = [ name = "frame-support" version = "28.0.0" dependencies = [ + "Inflector", "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-support-procedural 23.0.0", + "frame-system 28.0.0", "impl-trait-for-tuples", "k256", "log", @@ -6438,15 +7326,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", @@ -6454,6 +7342,48 @@ dependencies = [ "tt-call", ] +[[package]] +name = "frame-support" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e44af69fa61bc5005ffe0339e198957e77f0f255704a9bee720da18a733e3dc" +dependencies = [ + "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" @@ -6463,9 +7393,9 @@ dependencies = [ "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", @@ -6481,18 +7411,51 @@ dependencies = [ "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "static_assertions", - "syn 2.0.79", + "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 1.0.0", + "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.79", + "syn 2.0.87", ] [[package]] @@ -6501,19 +7464,30 @@ version = "11.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "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-benchmarking 28.0.0", + "frame-executive 28.0.0", "frame-metadata 16.0.0", - "frame-support", + "frame-support 28.0.0", "frame-support-test-pallet", - "frame-system", + "frame-system 28.0.0", "parity-scale-codec", "pretty_assertions", "rustversion", @@ -6535,8 +7509,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", @@ -6548,8 +7522,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", @@ -6561,7 +7535,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", ] @@ -6572,7 +7546,7 @@ dependencies = [ "cfg-if", "criterion", "docify", - "frame-support", + "frame-support 28.0.0", "log", "parity-scale-codec", "scale-info", @@ -6587,13 +7561,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", @@ -6603,6 +7598,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" @@ -6612,16 +7622,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" @@ -6644,7 +7677,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -6662,9 +7695,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", @@ -6687,9 +7720,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", @@ -6697,15 +7730,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", @@ -6715,9 +7748,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" @@ -6749,13 +7782,13 @@ 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.79", + "syn 2.0.87", ] [[package]] @@ -6770,27 +7803,31 @@ dependencies = [ [[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" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] [[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", @@ -6818,12 +7855,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]] @@ -6908,6 +7945,16 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator 0.3.0", + "stable_deref_trait", +] + [[package]] name = "glob" version = "0.3.1" @@ -6920,6 +7967,27 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 1.1.0", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-timers" version = "0.2.6" @@ -6932,49 +8000,62 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] 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]] @@ -7166,7 +8247,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" [[package]] -name = "hex-literal" +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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" @@ -7430,16 +8520,17 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", "hyper 1.3.1", "hyper-util", "log", - "rustls 0.23.10", + "rustls 0.23.14", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -7609,6 +8700,15 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941" +dependencies = [ + "parity-scale-codec", +] + [[package]] name = "impl-num-traits" version = "0.1.2" @@ -7617,7 +8717,18 @@ checksum = "951641f13f873bff03d4bf19ae8bec531935ac0ac2cc775f84d7edfdcfed3f17" dependencies = [ "integer-sqrt", "num-traits", - "uint", + "uint 0.9.5", +] + +[[package]] +name = "impl-num-traits" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803d15461ab0dcc56706adf266158acbc44ccf719bf7d0af30705f58b90a4b8c" +dependencies = [ + "integer-sqrt", + "num-traits", + "uint 0.10.0", ] [[package]] @@ -7626,7 +8737,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" dependencies = [ - "rlp", + "rlp 0.5.2", +] + +[[package]] +name = "impl-rlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54ed8ad1f3877f7e775b8cbf30ed1bd3209a95401817f19a0eb4402d13f8cf90" +dependencies = [ + "rlp 0.6.1", ] [[package]] @@ -7638,6 +8758,15 @@ dependencies = [ "serde", ] +[[package]] +name = "impl-serde" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a143eada6a1ec4aefa5049037a26a6d597bfd64f8c026d07b77133e02b7dd0b" +dependencies = [ + "serde", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -7806,7 +8935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.9", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -7873,6 +9002,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" @@ -7918,18 +9056,18 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[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", ] @@ -7977,99 +9115,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-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-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.10", - "rustls-pki-types", - "rustls-platform-verifier", - "soketto 0.8.0", - "thiserror", + "jsonrpsee-types", + "jsonrpsee-wasm-client", + "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.10", + "rustls 0.23.14", "rustls-pki-types", "rustls-platform-verifier", "soketto 0.8.0", @@ -8083,54 +9158,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-timer", - "futures-util", - "hyper 0.14.29", - "jsonrpsee-types 0.22.5", - "pin-project", - "rustc-hash 1.1.0", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "jsonrpsee-core" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" -dependencies = [ - "anyhow", - "async-trait", - "beef", - "futures-timer", - "futures-util", - "jsonrpsee-types 0.23.2", - "pin-project", - "rustc-hash 1.1.0", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "jsonrpsee-core" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" +checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" dependencies = [ "async-trait", "bytes", @@ -8139,7 +9169,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types", "parking_lot 0.12.3", "pin-project", "rand", @@ -8150,43 +9180,24 @@ dependencies = [ "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" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" +checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", "http-body 1.0.0", "hyper 1.3.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", - "rustls 0.23.10", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls 0.23.14", "rustls-platform-verifier", "serde", "serde_json", @@ -8199,22 +9210,22 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" +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.79", + "syn 2.0.87", ] [[package]] name = "jsonrpsee-server" -version = "0.24.3" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" +checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" dependencies = [ "futures-util", "http 1.1.0", @@ -8222,8 +9233,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", @@ -8239,35 +9250,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", @@ -8276,28 +9261,26 @@ dependencies = [ ] [[package]] -name = "jsonrpsee-ws-client" -version = "0.23.2" +name = "jsonrpsee-wasm-client" +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", ] @@ -8338,6 +9321,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1b8590eb6148af2ea2d75f38e7d29f5ca970d5a4df456b3ef19b8b415d0264" +dependencies = [ + "primitive-types 0.13.1", + "tiny-keccak", +] + [[package]] name = "keccak-hasher" version = "0.16.0" @@ -8364,12 +9357,13 @@ dependencies = [ "pallet-example-mbm", "pallet-example-tasks", "parity-scale-codec", - "polkadot-sdk", - "primitive-types", + "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]] @@ -8409,7 +9403,7 @@ dependencies = [ "rand", "rustls 0.21.7", "rustls-pemfile 1.0.3", - "secrecy", + "secrecy 0.8.0", "serde", "serde_json", "serde_yaml", @@ -8778,7 +9772,7 @@ dependencies = [ "sha2 0.10.8", "smallvec", "thiserror", - "uint", + "uint 0.9.5", "unsigned-varint 0.7.2", "void", ] @@ -8939,7 +9933,7 @@ dependencies = [ "proc-macro-warning 0.4.2", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9003,7 +9997,7 @@ dependencies = [ "futures", "js-sys", "libp2p-core", - "send_wrapper", + "send_wrapper 0.6.0", "wasm-bindgen", "wasm-bindgen-futures", ] @@ -9164,9 +10158,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lioness" @@ -9200,9 +10194,9 @@ dependencies = [ [[package]] name = "litep2p" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ab2528b02b6dbbc3e6ec4b55ccde885647c622a315b7da45081ed2dfe4b813" +checksum = "5b67484b8ac41e1cfdf012f65fa81e88c2ef5f8a7d6dec0e2678c2d06dc04530" dependencies = [ "async-trait", "bs58", @@ -9223,7 +10217,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "prost 0.12.6", - "prost-build 0.13.2", + "prost-build", "rand", "rcgen", "ring 0.16.20", @@ -9241,7 +10235,7 @@ dependencies = [ "tokio-tungstenite", "tokio-util", "tracing", - "uint", + "uint 0.9.5", "unsigned-varint 0.8.0", "url", "x25519-dalek", @@ -9356,7 +10350,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9370,7 +10364,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9381,7 +10375,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9392,7 +10386,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9524,7 +10518,7 @@ dependencies = [ "blake3", "frame-metadata 16.0.0", "parity-scale-codec", - "scale-decode", + "scale-decode 0.13.1", "scale-info", ] @@ -9546,7 +10540,7 @@ version = "0.1.0" dependencies = [ "async-std", "async-trait", - "bp-messages", + "bp-messages 0.7.0", "finality-relay", "futures", "hex", @@ -9578,9 +10572,9 @@ dependencies = [ "docify", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "minimal-template-runtime", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "serde_json", ] @@ -9590,7 +10584,7 @@ version = "0.0.0" dependencies = [ "pallet-minimal-template", "parity-scale-codec", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "scale-info", "serde_json", ] @@ -9655,9 +10649,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", @@ -9668,14 +10662,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", ] @@ -9729,7 +10723,7 @@ dependencies = [ "cfg-if", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -10071,7 +11065,7 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.6.0", "cfg-if", - "cfg_aliases 0.1.1", + "cfg_aliases", "libc", ] @@ -10092,8 +11086,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", @@ -10113,10 +11108,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", @@ -10134,7 +11129,7 @@ dependencies = [ name = "node-rpc" version = "3.0.0-dev" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "mmr-rpc", "node-primitives", "pallet-transaction-payment-rpc", @@ -10152,14 +11147,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", ] @@ -10191,18 +11186,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-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", @@ -10211,16 +11207,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", @@ -10333,7 +11329,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -10381,9 +11377,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", @@ -10509,7 +11505,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -10578,6 +11574,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "os_str_bytes" version = "6.5.1" @@ -10601,13 +11607,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", @@ -10616,18 +11622,38 @@ 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", + "primitive-types 0.13.1", "scale-info", "sp-api 26.0.0", "sp-arithmetic 23.0.0", @@ -10636,19 +11662,38 @@ 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", + "primitive-types 0.13.1", "scale-info", "sp-arithmetic 23.0.0", "sp-core 28.0.0", @@ -10656,16 +11701,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-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", @@ -10674,14 +11739,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", @@ -10690,16 +11770,31 @@ dependencies = [ ] [[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", +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 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", @@ -10710,16 +11805,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", @@ -10727,16 +11840,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", @@ -10744,13 +11874,29 @@ 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", + "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", @@ -10758,45 +11904,93 @@ dependencies = [ "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", @@ -10805,31 +11999,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]] @@ -10838,12 +12070,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", @@ -10852,13 +12084,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", ] @@ -10866,13 +12120,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", @@ -10885,11 +12139,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", @@ -10898,68 +12152,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", @@ -10967,24 +12283,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", @@ -10995,36 +12329,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", @@ -11034,20 +12388,40 @@ dependencies = [ "sp-trie 29.0.0", ] +[[package]] +name = "pallet-bridge-messages" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1decdc9fb885e46eb17f850aa14f8cf39e17f31574aa6a5fa1a9e603cc526a2" +dependencies = [ + "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", + "parity-scale-codec", + "scale-info", + "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-parachains" version = "0.7.0" dependencies = [ - "bp-header-chain", - "bp-parachains", - "bp-polkadot-core", - "bp-runtime", - "bp-test-utils", - "frame-benchmarking", - "frame-support", - "frame-system", + "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", + "pallet-bridge-grandpa 0.7.0", "parity-scale-codec", "scale-info", "sp-core 28.0.0", @@ -11056,27 +12430,48 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +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", - "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-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", @@ -11086,14 +12481,39 @@ dependencies = [ "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", @@ -11106,17 +12526,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", @@ -11124,40 +12563,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", @@ -11165,13 +12643,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", @@ -11179,6 +12674,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" @@ -11187,21 +12697,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", @@ -11217,19 +12727,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", @@ -11242,24 +12785,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", @@ -11268,19 +12811,66 @@ 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-proc-macro" -version = "18.0.0" -dependencies = [ +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]] +name = "pallet-contracts-proc-macro" +version = "18.0.0" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "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.79", + "syn 2.0.87", ] [[package]] @@ -11293,16 +12883,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", @@ -11311,15 +12914,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", @@ -11328,12 +12948,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", @@ -11345,36 +12984,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", @@ -11383,14 +13038,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", @@ -11398,29 +13071,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", ] @@ -11429,13 +13118,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", @@ -11443,53 +13132,127 @@ 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.2", + "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 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 31.0.0", + "sp-runtime 31.0.1", +] + [[package]] 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", @@ -11502,7 +13265,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", ] @@ -11510,11 +13273,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", @@ -11526,11 +13289,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", @@ -11540,8 +13303,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", @@ -11557,12 +13320,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", @@ -11575,9 +13338,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", @@ -11589,9 +13352,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", @@ -11605,7 +13368,8 @@ 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", "pallet-example-kitchensink", @@ -11620,70 +13384,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]] @@ -11691,11 +13516,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", @@ -11704,47 +13529,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-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", - "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", "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", @@ -11753,15 +13632,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", @@ -11769,13 +13662,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", @@ -11784,14 +13691,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", @@ -11807,23 +13731,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", @@ -11831,12 +13775,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", ] @@ -11844,9 +13806,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", @@ -11854,73 +13816,140 @@ 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-multisig" -version = "28.0.0" +name = "pallet-mmr" +version = "38.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6932dfb85f77a57c2d1fdc28a7b3a59ffe23efd8d5bb02dc3039d91347e4a3b" 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", "parity-scale-codec", "scale-info", - "sp-io 30.0.0", - "sp-runtime 31.0.1", + "sp-core 34.0.0", + "sp-io 38.0.0", + "sp-mmr-primitives 34.1.0", + "sp-runtime 39.0.2", ] [[package]] -name = "pallet-nft-fractionalization" -version = "10.0.0" +name = "pallet-multisig" +version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", "log", - "pallet-assets", - "pallet-balances", - "pallet-nfts", + "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-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", + "scale-info", + "sp-io 38.0.0", + "sp-runtime 39.0.2", +] + +[[package]] +name = "pallet-nft-fractionalization" +version = "10.0.0" +dependencies = [ + "frame-benchmarking 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "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", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "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", @@ -11929,23 +13958,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", @@ -11954,12 +14012,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", @@ -11968,56 +14042,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", @@ -12028,32 +14158,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", ] @@ -12062,22 +14203,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", ] @@ -12086,43 +14227,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]] @@ -12130,9 +14312,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", @@ -12141,14 +14323,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", ] @@ -12156,14 +14356,9 @@ dependencies = [ name = "pallet-parachain-template" version = "0.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", "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]] @@ -12171,10 +14366,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", @@ -12185,15 +14380,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", @@ -12201,29 +14414,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 = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "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", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", +] + +[[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", + "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", @@ -12234,14 +14474,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", @@ -12249,18 +14508,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", @@ -12270,13 +14544,31 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +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", @@ -12285,6 +14577,23 @@ 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" @@ -12292,38 +14601,116 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags 1.3.2", + "derive_more 0.99.17", "environmental", - "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", - "log", - "pallet-assets", - "pallet-balances", - "pallet-message-queue", - "pallet-proxy", - "pallet-revive-fixtures", - "pallet-revive-proc-macro", - "pallet-revive-uapi", - "pallet-timestamp", - "pallet-utility", + "jsonrpsee", + "log", + "pallet-assets 29.1.0", + "pallet-balances 28.0.0", + "pallet-message-queue 31.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.11.0", + "polkavm 0.13.0", "pretty_assertions", - "rlp", + "rlp 0.6.1", "scale-info", + "secp256k1 0.28.2", "serde", + "serde_json", "sp-api 26.0.0", + "sp-arithmetic 23.0.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", - "staging-xcm", - "staging-xcm-builder", - "wat", + "sp-weights 27.0.0", + "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" +dependencies = [ + "anyhow", + "clap 4.5.13", + "env_logger 0.11.3", + "ethabi", + "futures", + "hex", + "hex-literal", + "jsonrpsee", + "log", + "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 0.28.2", + "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", + "subxt-signer", + "thiserror", + "tokio", ] [[package]] @@ -12331,10 +14718,10 @@ name = "pallet-revive-fixtures" version = "0.1.0" dependencies = [ "anyhow", - "frame-system", + "frame-system 28.0.0", "log", "parity-wasm", - "polkavm-linker 0.11.0", + "polkavm-linker 0.14.0", "sp-core 28.0.0", "sp-io 30.0.0", "sp-runtime 31.0.1", @@ -12342,28 +14729,43 @@ dependencies = [ "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", +] + [[package]] 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-proxy 28.0.0", + "pallet-revive 0.1.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-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", @@ -12372,10 +14774,45 @@ 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-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]] @@ -12384,7 +14821,18 @@ version = "0.1.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "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]] @@ -12394,7 +14842,20 @@ dependencies = [ "bitflags 1.3.2", "parity-scale-codec", "paste", - "polkavm-derive 0.11.0", + "polkavm-derive 0.14.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", ] @@ -12402,29 +14863,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", @@ -12432,17 +14909,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", @@ -12451,15 +14943,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", @@ -12468,14 +14979,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", @@ -12491,11 +15021,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", @@ -12505,13 +15035,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", @@ -12519,69 +15067,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", @@ -12592,21 +15206,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", @@ -12614,13 +15246,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" @@ -12629,7 +15283,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-runtime 31.0.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12640,25 +15294,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", @@ -12673,21 +15348,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]] @@ -12695,9 +15405,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", @@ -12705,13 +15415,29 @@ 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", @@ -12724,30 +15450,50 @@ name = "pallet-timestamp" 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", "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-storage 19.0.0", - "sp-timestamp", + "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-tips" 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", "serde", @@ -12757,13 +15503,33 @@ dependencies = [ "sp-storage 19.0.0", ] +[[package]] +name = "pallet-tips" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1d4371a70c309ba11624933f8f5262fe4edad0149c556361d31f26190da936" +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", + "serde", + "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-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", @@ -12773,12 +15539,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", @@ -12789,53 +15571,106 @@ dependencies = [ ] [[package]] -name = "pallet-transaction-payment-rpc-runtime-api" -version = "28.0.0" +name = "pallet-transaction-payment-rpc-runtime-api" +version = "28.0.0" +dependencies = [ + "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 28.0.0", + "frame-support 28.0.0", + "frame-system 28.0.0", + "log", + "pallet-balances 28.0.0", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 28.0.0", + "sp-inherents 26.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "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 = [ - "pallet-transaction-payment", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", + "log", + "pallet-balances 39.0.0", "parity-scale-codec", - "sp-api 26.0.0", - "sp-runtime 31.0.1", - "sp-weights 27.0.0", + "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]] -name = "pallet-transaction-storage" +name = "pallet-treasury" version = "27.0.0" dependencies = [ - "array-bytes", - "frame-benchmarking", - "frame-support", - "frame-system", + "docify", + "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", + "pallet-utility 28.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-transaction-storage-proof", ] [[package]] name = "pallet-treasury" -version = "27.0.0" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98bfdd3bb9b58fb010bcd419ff5bf940817a8e404cdbf7886a53ac730f5dda2b" dependencies = [ "docify", - "frame-benchmarking", - "frame-support", - "frame-system", + "frame-benchmarking 38.0.0", + "frame-support 38.0.0", + "frame-system 38.0.0", "impl-trait-for-tuples", - "pallet-balances", - "pallet-utility", + "pallet-balances 39.0.0", "parity-scale-codec", "scale-info", "serde", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", + "sp-core 34.0.0", + "sp-runtime 39.0.2", ] [[package]] @@ -12843,12 +15678,12 @@ 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", @@ -12856,15 +15691,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", @@ -12873,33 +15726,83 @@ 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", + "sp-io 30.0.0", + "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 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", "sp-io 30.0.0", "sp-runtime 31.0.1", + "sp-weights 27.0.0", ] [[package]] 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", @@ -12907,15 +15810,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", @@ -12924,88 +15842,169 @@ 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", - "log", - "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", - "xcm-runtime-apis", + "staging-xcm 7.0.0", + "staging-xcm-builder 7.0.0", + "staging-xcm-executor 7.0.0", + "tracing", + "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", + "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", @@ -13013,8 +16012,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]] @@ -13023,57 +16042,16 @@ version = "0.0.0" dependencies = [ "clap 4.5.13", "color-print", - "cumulus-client-cli", - "cumulus-client-collator", - "cumulus-client-consensus-aura", - "cumulus-client-consensus-common", - "cumulus-client-consensus-proposer", - "cumulus-client-service", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-relay-chain-interface", "docify", - "frame-benchmarking", - "frame-benchmarking-cli", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", - "pallet-transaction-payment-rpc", "parachain-template-runtime", "parity-scale-codec", - "polkadot-cli", - "polkadot-primitives", - "sc-basic-authorship", - "sc-chain-spec", - "sc-cli", - "sc-client-api", - "sc-consensus", - "sc-executor 0.32.0", - "sc-network", - "sc-network-sync", - "sc-offchain", - "sc-rpc", - "sc-service", - "sc-sysinfo", - "sc-telemetry", + "polkadot-sdk 0.1.0", "sc-tracing", - "sc-transaction-pool", - "sc-transaction-pool-api", "serde", "serde_json", - "sp-api 26.0.0", - "sp-block-builder", - "sp-blockchain", - "sp-consensus-aura", - "sp-core 28.0.0", - "sp-genesis-builder", - "sp-io 30.0.0", - "sp-keystore 0.34.0", - "sp-runtime 31.0.1", - "sp-timestamp", - "staging-xcm", - "substrate-build-script-utils", - "substrate-frame-rpc-system", "substrate-prometheus-endpoint", ] @@ -13081,90 +16059,77 @@ dependencies = [ name = "parachain-template-runtime" version = "0.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", + "cumulus-pallet-parachain-system 0.7.0", "docify", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", "pallet-parachain-template", - "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-runtime-common", + "polkadot-sdk 0.1.0", "scale-info", "serde_json", "smallvec", - "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", - "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime 31.0.1", - "sp-session", - "sp-transaction-pool", - "sp-version 29.0.0", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "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]] @@ -13173,7 +16138,7 @@ version = "0.1.0" dependencies = [ "async-std", "async-trait", - "bp-polkadot-core", + "bp-polkadot-core 0.7.0", "futures", "log", "parity-scale-codec", @@ -13186,30 +16151,61 @@ 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", "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", +] + +[[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]] @@ -13285,13 +16281,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" dependencies = [ "cfg-if", - "ethereum-types", + "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", + "primitive-types 0.12.2", "smallvec", "winapi", ] @@ -13397,6 +16393,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest 0.10.7", + "hmac 0.12.1", "password-hash", ] @@ -13429,208 +16426,211 @@ 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", - "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", - "primitive-types", + "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-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", + "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-constants 7.0.0", "westend-system-emulated-network", ] @@ -13638,66 +16638,67 @@ 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-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", + "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]] @@ -13736,7 +16737,7 @@ dependencies = [ "pest_meta", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -13762,22 +16763,22 @@ dependencies = [ [[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.79", + "syn 2.0.87", ] [[package]] @@ -13810,9 +16811,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.0.2" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "0e4c7666f2019727f9e8e14bf14456e99c707d780922869f1ba473eee101fa49" [[package]] name = "plotters" @@ -13850,7 +16851,7 @@ dependencies = [ "color-eyre", "nix 0.28.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", @@ -13879,7 +16880,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", @@ -13887,7 +16888,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", @@ -13907,13 +16908,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", @@ -13924,7 +16925,7 @@ name = "polkadot-availability-distribution" version = "7.0.0" dependencies = [ "assert_matches", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "futures-timer", @@ -13935,7 +16936,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", @@ -13943,7 +16944,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", @@ -13967,7 +16968,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", @@ -13976,7 +16977,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", @@ -14015,7 +17016,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", @@ -14037,14 +17038,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", @@ -14063,6 +17064,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" @@ -14070,7 +17083,7 @@ dependencies = [ "assert_matches", "async-channel 1.9.0", "async-trait", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "futures-timer", @@ -14082,13 +17095,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", @@ -14102,7 +17115,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", @@ -14123,18 +17136,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", @@ -14159,12 +17172,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", ] @@ -14181,11 +17194,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", @@ -14198,7 +17212,7 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "derive_more", + "derive_more 0.99.17", "futures", "futures-timer", "itertools 0.11.0", @@ -14213,7 +17227,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", @@ -14224,10 +17238,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", @@ -14256,7 +17270,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", @@ -14266,10 +17280,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", @@ -14296,11 +17310,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", @@ -14319,7 +17333,8 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", - "polkadot-primitives", + "polkadot-parachain-primitives 6.0.0", + "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "polkadot-statement-table", "rstest", @@ -14327,7 +17342,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", @@ -14342,7 +17357,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", @@ -14366,12 +17381,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", @@ -14389,7 +17405,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", @@ -14412,7 +17428,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", @@ -14433,13 +17449,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", @@ -14455,9 +17471,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", ] @@ -14472,7 +17488,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", @@ -14494,7 +17510,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", @@ -14521,7 +17537,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", @@ -14529,16 +17545,19 @@ 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", + "strum 0.26.3", "tempfile", "test-parachain-adder", "test-parachain-halt", @@ -14558,12 +17577,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", @@ -14581,8 +17600,8 @@ dependencies = [ "libc", "nix 0.28.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", @@ -14608,8 +17627,8 @@ dependencies = [ "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", ] @@ -14626,7 +17645,7 @@ dependencies = [ "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", @@ -14649,13 +17668,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", ] @@ -14672,14 +17691,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", @@ -14694,20 +17713,20 @@ 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", "sc-network", "sc-network-types", "sp-runtime 31.0.1", - "strum 0.26.2", + "strum 0.26.3", "thiserror", "tracing-gum", ] @@ -14722,14 +17741,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", @@ -14757,13 +17776,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", ] @@ -14773,13 +17792,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", @@ -14787,9 +17806,9 @@ 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", "substrate-prometheus-endpoint", "thiserror", @@ -14801,7 +17820,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "derive_more", + "derive_more 0.99.17", "fatality", "futures", "futures-channel", @@ -14822,7 +17841,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", @@ -14836,6 +17855,89 @@ dependencies = [ "tracing-gum", ] +[[package]] +name = "polkadot-omni-node" +version = "0.1.0" +dependencies = [ + "color-eyre", + "polkadot-omni-node-lib", + "substrate-build-script-utils", +] + +[[package]] +name = "polkadot-omni-node-lib" +version = "0.1.0" +dependencies = [ + "assert_cmd", + "async-trait", + "clap 4.5.13", + "color-print", + "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-parachain-inherent", + "cumulus-client-service", + "cumulus-primitives-aura 0.7.0", + "cumulus-primitives-core 0.7.0", + "cumulus-relay-chain-interface", + "docify", + "frame-benchmarking 28.0.0", + "frame-benchmarking-cli", + "frame-support 28.0.0", + "frame-system-rpc-runtime-api 26.0.0", + "frame-try-runtime 0.34.0", + "futures", + "futures-timer", + "jsonrpsee", + "log", + "nix 0.28.0", + "pallet-transaction-payment 28.0.0", + "pallet-transaction-payment-rpc", + "pallet-transaction-payment-rpc-runtime-api 28.0.0", + "parachains-common 7.0.0", + "parity-scale-codec", + "polkadot-cli", + "polkadot-primitives 7.0.0", + "sc-basic-authorship", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-client-db", + "sc-consensus", + "sc-consensus-manual-seal", + "sc-executor 0.32.0", + "sc-network", + "sc-rpc", + "sc-service", + "sc-sysinfo", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "serde", + "serde_json", + "sp-api 26.0.0", + "sp-block-builder 26.0.0", + "sp-consensus-aura 0.32.0", + "sp-core 28.0.0", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-session 27.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", + "tokio", + "wait-timeout", +] + [[package]] name = "polkadot-overseer" version = "7.0.0" @@ -14852,7 +17954,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", @@ -14868,7 +17970,6 @@ version = "4.0.0" dependencies = [ "asset-hub-rococo-runtime", "asset-hub-westend-runtime", - "bp-messages", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", "collectives-westend-runtime", @@ -14876,15 +17977,15 @@ 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", - "polkadot-parachain-lib", + "polkadot-omni-node-lib", "rococo-parachain-runtime", "sc-chain-spec", "sc-cli", @@ -14892,99 +17993,42 @@ dependencies = [ "serde", "serde_json", "sp-core 28.0.0", - "sp-genesis-builder", - "staging-xcm", + "sp-genesis-builder 0.8.0", + "sp-keyring 31.0.0", + "staging-xcm 7.0.0", "substrate-build-script-utils", - "testnet-parachains-constants", ] [[package]] -name = "polkadot-parachain-lib" -version = "0.1.0" +name = "polkadot-parachain-primitives" +version = "6.0.0" dependencies = [ - "assert_cmd", - "async-trait", - "clap 4.5.13", - "color-print", - "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-parachain-inherent", - "cumulus-client-service", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-relay-chain-interface", - "docify", - "frame-benchmarking", - "frame-benchmarking-cli", - "frame-support", - "frame-system-rpc-runtime-api", - "frame-try-runtime", - "futures", - "futures-timer", - "jsonrpsee 0.24.3", - "log", - "nix 0.28.0", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc", - "pallet-transaction-payment-rpc-runtime-api", - "parachains-common", + "bounded-collections", + "derive_more 0.99.17", "parity-scale-codec", - "polkadot-cli", - "polkadot-primitives", - "sc-basic-authorship", - "sc-chain-spec", - "sc-cli", - "sc-client-api", - "sc-client-db", - "sc-consensus", - "sc-consensus-manual-seal", - "sc-executor 0.32.0", - "sc-network", - "sc-rpc", - "sc-service", - "sc-sysinfo", - "sc-telemetry", - "sc-tracing", - "sc-transaction-pool", + "polkadot-core-primitives 7.0.0", + "scale-info", "serde", - "serde_json", - "sp-api 26.0.0", - "sp-block-builder", - "sp-consensus-aura", "sp-core 28.0.0", - "sp-genesis-builder", - "sp-inherents", - "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-session", - "sp-timestamp", - "sp-transaction-pool", - "sp-version 29.0.0", "sp-weights 27.0.0", - "substrate-frame-rpc-system", - "substrate-prometheus-endpoint", - "substrate-state-trie-migration-rpc", - "tokio", - "wait-timeout", ] [[package]] name = "polkadot-parachain-primitives" -version = "6.0.0" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5648a2e8ce1f9a0f8c41c38def670cefd91932cd793468e1a5b0b0b4e4af1" dependencies = [ "bounded-collections", - "derive_more", + "derive_more 0.99.17", "parity-scale-codec", - "polkadot-core-primitives", + "polkadot-core-primitives 15.0.0", "scale-info", "serde", - "sp-core 28.0.0", - "sp-runtime 31.0.1", - "sp-weights 27.0.0", + "sp-core 34.0.0", + "sp-runtime 39.0.2", + "sp-weights 31.0.0", ] [[package]] @@ -14995,34 +18039,89 @@ dependencies = [ "hex-literal", "log", "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain-primitives", + "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", - "sp-consensus-slots", + "sp-authority-discovery 26.0.0", + "sp-consensus-slots 0.32.0", "sp-core 28.0.0", - "sp-inherents", + "sp-inherents 26.0.0", "sp-io 30.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "sp-staking", + "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 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", ] @@ -15030,10 +18129,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", @@ -15049,11 +18148,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", @@ -15065,53 +18164,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", ] @@ -15120,12 +18269,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" @@ -15133,32 +18295,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", @@ -15171,41 +18333,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", @@ -15216,166 +18427,168 @@ 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-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-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 0.1.0", + "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-vesting", - "pallet-whitelist", - "pallet-xcm", - "pallet-xcm-benchmarks", - "pallet-xcm-bridge-hub", - "pallet-xcm-bridge-hub-router", - "parachains-common", - "parachains-runtimes-test-utils", + "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 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", @@ -15405,15 +18618,15 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", + "polkadot-omni-node-lib", "polkadot-overseer", - "polkadot-parachain-lib", - "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", @@ -15471,38 +18684,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", @@ -15510,32 +18723,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", @@ -15543,11 +18756,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", @@ -15556,65 +18769,305 @@ 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]] name = "polkadot-sdk-docs" version = "0.0.1" dependencies = [ + "assert_cmd", "chain-spec-guide-runtime", "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-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-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-sdk", - "polkadot-sdk-frame", + "polkadot-omni-node-lib", + "polkadot-sdk 0.1.0", + "polkadot-sdk-docs-first-pallet", + "polkadot-sdk-docs-first-runtime", + "polkadot-sdk-frame 0.1.0", + "rand", "sc-chain-spec", "sc-cli", "sc-client-db", @@ -15630,30 +19083,61 @@ dependencies = [ "sc-rpc-api", "sc-service", "scale-info", + "serde_json", "simple-mermaid 0.1.1", "solochain-template-runtime", "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", "sp-tracing 16.0.0", "sp-version 29.0.0", + "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]] +name = "polkadot-sdk-docs-first-pallet" +version = "0.0.0" +dependencies = [ + "docify", + "parity-scale-codec", + "polkadot-sdk-frame 0.1.0", + "scale-info", +] + +[[package]] +name = "polkadot-sdk-docs-first-runtime" +version = "0.0.0" +dependencies = [ + "docify", + "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 0.1.0", + "scale-info", + "serde_json", + "sp-keyring 31.0.0", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -15661,52 +19145,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-inherents", + "sp-genesis-builder 0.8.0", + "sp-inherents 26.0.0", "sp-io 30.0.0", - "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", @@ -15715,7 +19234,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", @@ -15742,14 +19261,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", @@ -15772,37 +19291,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]] @@ -15823,18 +19341,19 @@ 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_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", @@ -15845,7 +19364,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", ] @@ -15889,7 +19408,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", @@ -15911,14 +19430,14 @@ 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.2", + "strum 0.26.3", "substrate-prometheus-endpoint", "tikv-jemallocator", "tokio", @@ -15929,11 +19448,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", @@ -15943,14 +19462,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", ] @@ -15978,7 +19497,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", @@ -15990,58 +19509,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", ] @@ -16050,20 +19569,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", @@ -16080,14 +19599,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", @@ -16141,15 +19660,28 @@ dependencies = [ [[package]] name = "polkavm" -version = "0.11.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.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1195fbc12f11645143a4f3974bf909d25c7f7efddcc6f4e57688d9a518c90bae" +checksum = "57e79a14b15ed38cb5b9a1e38d02e933f19e3d180ae5b325fed606c5e5b9177e" dependencies = [ "libc", "log", - "polkavm-assembler 0.11.0", - "polkavm-common 0.11.0", - "polkavm-linux-raw 0.11.0", + "polkavm-assembler 0.13.0", + "polkavm-common 0.13.0", + "polkavm-linux-raw 0.13.0", ] [[package]] @@ -16163,9 +19695,18 @@ dependencies = [ [[package]] name = "polkavm-assembler" -version = "0.11.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.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b0399659fe7a5370c3e3464188888d29069cfa46d99631d19834a379c15826" +checksum = "4e8da55465000feb0a61bbf556ed03024db58f3420eca37721fc726b3b2136bf" dependencies = [ "log", ] @@ -16187,14 +19728,30 @@ dependencies = [ [[package]] name = "polkavm-common" -version = "0.11.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0097b48bc0bedf9f3f537ce8f37e8f1202d8d83f9b621bdb21ff2c59b9097c50" +dependencies = [ + "log", + "polkavm-assembler 0.10.0", +] + +[[package]] +name = "polkavm-common" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254b19b64ff9b57c06b32c0affed961cb9a32429b8d3e5cf2633cad7fbb3e270" +checksum = "084b4339aae7dfdaaa5aa7d634110afd95970e0737b6fb2a0cb10db8b56b753c" dependencies = [ "log", - "polkavm-assembler 0.11.0", + "polkavm-assembler 0.13.0", ] +[[package]] +name = "polkavm-common" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711952a783e9c5ad407cdacb1ed147f36d37c5d43417c1091d86456d2999417b" + [[package]] name = "polkavm-derive" version = "0.8.0" @@ -16215,11 +19772,20 @@ dependencies = [ [[package]] name = "polkavm-derive" -version = "0.11.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.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f565f0106fbb3598d64b8528d5cb966b6a87a8dd93fbcfe09fb6388ff2865711" +checksum = "b4832a0aebf6cefc988bb7b2d74ea8c86c983164672e2fc96300f356a1babfc1" dependencies = [ - "polkavm-derive-impl-macro 0.11.0", + "polkavm-derive-impl-macro 0.14.0", ] [[package]] @@ -16231,7 +19797,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16243,19 +19809,31 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "polkavm-derive-impl" -version = "0.11.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314445fb5688b4769354087d92be2ac94c487e63ffe74a6fb7bb312e57f20827" +checksum = "7855353a5a783dd5d09e3b915474bddf66575f5a3cf45dec8d1c5e051ba320dc" dependencies = [ - "polkavm-common 0.11.0", + "polkavm-common 0.10.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e339fc7c11310fe5adf711d9342278ac44a75c9784947937cce12bd4f30842f2" +dependencies = [ + "polkavm-common 0.14.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -16265,7 +19843,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16275,45 +19853,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "polkavm-derive-impl-macro" -version = "0.11.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.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf952e05bc5ce7d81293bae18cb44c271c78615b201d75e983cdcc40d5c6ef1" +checksum = "b569754b15060d03000c09e3bf11509d527f60b75d79b4c30c3625b5071d9702" dependencies = [ - "polkavm-derive-impl 0.11.0", - "syn 2.0.79", + "polkavm-derive-impl 0.14.0", + "syn 2.0.87", ] [[package]] name = "polkavm-linker" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" +checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" +dependencies = [ + "gimli 0.28.0", + "hashbrown 0.14.5", + "log", + "object 0.32.2", + "polkavm-common 0.9.0", + "regalloc2 0.9.3", + "rustc-demangle", +] + +[[package]] +name = "polkavm-linker" +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.32.2", - "polkavm-common 0.9.0", + "object 0.36.1", + "polkavm-common 0.10.0", "regalloc2 0.9.3", "rustc-demangle", ] [[package]] name = "polkavm-linker" -version = "0.11.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535a2095a186ccde2cd2fa721d6370c495586d47714817565b2f6621d31164b3" +checksum = "0959ac3b0f4fd5caf5c245c637705f19493efe83dba31a83bbba928b93b0116a" dependencies = [ - "gimli 0.28.0", + "gimli 0.31.1", "hashbrown 0.14.5", "log", "object 0.36.1", - "polkavm-common 0.11.0", + "polkavm-common 0.14.0", "regalloc2 0.9.3", "rustc-demangle", ] @@ -16326,9 +19929,15 @@ checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" [[package]] name = "polkavm-linux-raw" -version = "0.11.0" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26e45fa59c7e1bb12ef5289080601e9ec9b31435f6e32800a5c90c132453d126" + +[[package]] +name = "polkavm-linux-raw" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011697430dfcfe800d1d7c540ef69e3bdd66e9037cc38f01fee1c2e0908011e" +checksum = "686c4dd9c9c16cc22565b51bdbb269792318d0fd2e6b966b5f6c788534cad0e9" [[package]] name = "polling" @@ -16355,7 +19964,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.21", + "rustix 0.38.25", "tracing", "windows-sys 0.52.0", ] @@ -16502,7 +20111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2 1.0.86", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16512,12 +20121,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", - "impl-codec", - "impl-num-traits", - "impl-rlp", - "impl-serde", + "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", +] + +[[package]] +name = "primitive-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" +dependencies = [ + "fixed-hash", + "impl-codec 0.7.0", + "impl-num-traits 0.2.0", + "impl-rlp 0.4.0", + "impl-serde 0.5.0", "scale-info", - "uint", + "uint 0.10.0", ] [[package]] @@ -16528,7 +20152,7 @@ checksum = "a172e6cc603231f2cf004232eabcecccc0da53ba576ab286ef7baa0cfc7927ad" dependencies = [ "coarsetime", "crossbeam-queue", - "derive_more", + "derive_more 0.99.17", "futures", "futures-timer", "nanorand", @@ -16579,6 +20203,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -16593,7 +20239,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16604,7 +20250,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16637,7 +20283,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.21", + "rustix 0.38.25", ] [[package]] @@ -16685,7 +20331,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16714,7 +20360,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -16750,27 +20396,6 @@ dependencies = [ "prost-derive 0.13.2", ] -[[package]] -name = "prost-build" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" -dependencies = [ - "bytes", - "heck 0.5.0", - "itertools 0.11.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost 0.12.6", - "prost-types 0.12.4", - "regex", - "syn 2.0.79", - "tempfile", -] - [[package]] name = "prost-build" version = "0.13.2" @@ -16779,16 +20404,16 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.11.0", + "itertools 0.13.0", "log", "multimap", "once_cell", "petgraph", "prettyplease", "prost 0.13.2", - "prost-types 0.13.2", + "prost-types", "regex", - "syn 2.0.79", + "syn 2.0.87", "tempfile", ] @@ -16812,10 +20437,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -16825,19 +20450,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.13.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", -] - -[[package]] -name = "prost-types" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" -dependencies = [ - "prost 0.12.6", + "syn 2.0.87", ] [[package]] @@ -16992,7 +20608,7 @@ dependencies = [ "quinn-proto 0.11.8", "quinn-udp 0.5.4", "rustc-hash 2.0.0", - "rustls 0.23.10", + "rustls 0.23.14", "socket2 0.5.7", "thiserror", "tokio", @@ -17026,7 +20642,7 @@ dependencies = [ "rand", "ring 0.17.7", "rustc-hash 2.0.0", - "rustls 0.23.10", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -17214,22 +20830,6 @@ dependencies = [ "yasna", ] -[[package]] -name = "reconnecting-jsonrpsee-ws-client" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06fa4f17e09edfc3131636082faaec633c7baa269396b4004040bc6c52f49f65" -dependencies = [ - "cfg_aliases 0.2.1", - "finito", - "futures", - "jsonrpsee 0.23.2", - "serde_json", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -17274,7 +20874,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", @@ -17297,7 +20897,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -17327,14 +20927,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.9", + "regex-syntax 0.8.5", ] [[package]] @@ -17354,13 +20954,13 @@ checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -17371,9 +20971,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" @@ -17387,19 +20987,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", @@ -17409,14 +21009,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", ] @@ -17429,7 +21029,7 @@ dependencies = [ "async-std", "async-trait", "backoff", - "bp-runtime", + "bp-runtime 0.7.0", "console", "futures", "isahc", @@ -17452,14 +21052,14 @@ 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]] @@ -17519,7 +21119,7 @@ dependencies = [ "http-body 1.0.0", "http-body-util", "hyper 1.3.1", - "hyper-rustls 0.27.2", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "js-sys", @@ -17529,7 +21129,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn 0.11.5", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pemfile 2.0.0", "rustls-pki-types", "serde", @@ -17613,6 +21213,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -17629,6 +21238,16 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlp" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24e92bb2a83198bb76d661a71df9f7076b8c420b8696e4d3d97d50d94479e3" +dependencies = [ + "bytes", + "rustc-hex", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -17644,136 +21263,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 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-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", @@ -17782,49 +21403,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]] @@ -17896,7 +21534,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.79", + "syn 2.0.87", "unicode-ident", ] @@ -17939,10 +21577,10 @@ dependencies = [ "num-bigint", "num-traits", "parity-scale-codec", - "primitive-types", + "primitive-types 0.12.2", "proptest", "rand", - "rlp", + "rlp 0.5.2", "ruint-macro", "serde", "valuable", @@ -18045,14 +21683,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.10", + "linux-raw-sys 0.4.11", "windows-sys 0.48.0", ] @@ -18088,22 +21726,22 @@ dependencies = [ "log", "ring 0.17.7", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle 2.5.0", "zeroize", ] [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", "ring 0.17.7", "rustls-pki-types", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "subtle 2.5.0", "zeroize", ] @@ -18133,6 +21771,19 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.0.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.3" @@ -18154,9 +21805,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-platform-verifier" @@ -18169,10 +21820,10 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-native-certs 0.7.0", "rustls-platform-verifier-android", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "security-framework", "security-framework-sys", "webpki-roots 0.26.3", @@ -18197,9 +21848,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring 0.17.7", "rustls-pki-types", @@ -18237,13 +21888,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]] @@ -18281,6 +21931,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" @@ -18308,7 +21967,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", ] @@ -18320,20 +21991,19 @@ dependencies = [ "futures", "futures-timer", "ip_network", - "libp2p", "linked_hash_set", "log", "multihash 0.19.1", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "quickcheck", "rand", "sc-client-api", "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", @@ -18363,7 +22033,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", @@ -18375,10 +22045,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", @@ -18405,12 +22075,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", @@ -18424,7 +22094,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -18454,12 +22124,13 @@ dependencies = [ "sc-service", "sc-telemetry", "sc-tracing", + "sc-transaction-pool", "sc-utils", "serde", "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", @@ -18490,7 +22161,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", @@ -18576,17 +22247,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", @@ -18618,18 +22289,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", @@ -18642,7 +22313,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", @@ -18655,9 +22326,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", @@ -18692,13 +22363,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", @@ -18714,7 +22385,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", @@ -18723,7 +22394,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", @@ -18780,10 +22451,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", @@ -18799,7 +22470,7 @@ version = "0.19.0" dependencies = [ "finality-grandpa", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "sc-block-builder", @@ -18808,9 +22479,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", @@ -18825,7 +22496,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "sc-basic-authorship", @@ -18840,14 +22511,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", @@ -18868,12 +22539,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", @@ -18894,9 +22565,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", @@ -18961,7 +22632,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", ] @@ -18986,7 +22681,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", ] @@ -19010,7 +22719,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]] @@ -19052,7 +22773,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", ] @@ -19109,7 +22849,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", ] @@ -19125,6 +22865,7 @@ dependencies = [ "asynchronous-codec", "bytes", "cid 0.9.0", + "criterion", "either", "fnv", "futures", @@ -19142,10 +22883,11 @@ dependencies = [ "partial_sort", "pin-project", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "rand", "sc-block-builder", "sc-client-api", + "sc-consensus", "sc-network-common", "sc-network-light", "sc-network-sync", @@ -19187,11 +22929,11 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build 0.12.4", + "prost-build", "sc-consensus", "sc-network-types", "sp-consensus", - "sp-consensus-grandpa", + "sp-consensus-grandpa 13.0.0", "sp-runtime 31.0.1", "tempfile", ] @@ -19229,7 +22971,7 @@ dependencies = [ "log", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "sc-client-api", "sc-network", "sc-network-types", @@ -19254,7 +22996,7 @@ dependencies = [ "sc-network-types", "sp-consensus", "sp-runtime 31.0.1", - "sp-statement-store", + "sp-statement-store 10.0.0", "substrate-prometheus-endpoint", ] @@ -19272,7 +23014,7 @@ dependencies = [ "mockall 0.11.4", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "quickcheck", "sc-block-builder", "sc-client-api", @@ -19286,7 +23028,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", @@ -19352,8 +23094,10 @@ name = "sc-network-types" version = "0.10.0" dependencies = [ "bs58", + "bytes", "ed25519-dalek", "libp2p-identity", + "libp2p-kad", "litep2p", "log", "multiaddr 0.18.1", @@ -19374,14 +23118,17 @@ dependencies = [ "fnv", "futures", "futures-timer", - "hyper 0.14.29", - "hyper-rustls 0.24.2", + "http-body-util", + "hyper 1.3.1", + "hyper-rustls 0.27.3", + "hyper-util", "log", "num_cpus", "once_cell", "parity-scale-codec", "parking_lot 0.12.3", "rand", + "rustls 0.23.14", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -19396,7 +23143,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", @@ -19419,7 +23166,7 @@ version = "29.0.0" dependencies = [ "assert_matches", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19443,11 +23190,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", @@ -19457,7 +23204,7 @@ dependencies = [ name = "sc-rpc-api" version = "0.33.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee", "parity-scale-codec", "sc-chain-spec", "sc-mixnet", @@ -19484,7 +23231,7 @@ dependencies = [ "http-body-util", "hyper 1.3.1", "ip_network", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "sc-rpc-api", "serde", @@ -19501,10 +23248,11 @@ version = "0.34.0" dependencies = [ "array-bytes", "assert_matches", + "async-trait", "futures", "futures-util", "hex", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19546,7 +23294,7 @@ 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]] @@ -19558,7 +23306,7 @@ dependencies = [ "exit-future", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19596,11 +23344,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", @@ -19673,7 +23421,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", @@ -19696,7 +23444,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", @@ -19714,7 +23462,7 @@ dependencies = [ name = "sc-sysinfo" version = "27.0.0" dependencies = [ - "derive_more", + "derive_more 0.99.17", "futures", "libc", "log", @@ -19786,7 +23534,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -19799,6 +23547,8 @@ dependencies = [ "criterion", "futures", "futures-timer", + "indexmap 2.2.3", + "itertools 0.11.0", "linked-hash-map", "log", "parity-scale-codec", @@ -19815,12 +23565,14 @@ 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", "substrate-test-runtime-transaction-pool", "thiserror", + "tokio", + "tokio-stream", ] [[package]] @@ -19871,9 +23623,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", + "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", + "primitive-types 0.13.1", "scale-bits", "scale-decode-derive", "scale-type-resolver", @@ -19882,25 +23647,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", + "primitive-types 0.13.1", "scale-bits", "scale-encode-derive", "scale-type-resolver", @@ -19909,26 +23674,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.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "1aa7ffc1c0ef49b0452c6e2986abf2b07743320641ffd5fc63d552458e3b779b" dependencies = [ "bitvec", "cfg-if", - "derive_more", + "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", "serde", @@ -19936,14 +23701,14 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.3" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "46385cc24172cf615450267463f937c10072516359b3ff1cb24228a4a08bf951" 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]] @@ -19958,31 +23723,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.79", + "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", @@ -20087,6 +23851,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" @@ -20125,16 +23901,36 @@ dependencies = [ name = "secp256k1" version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +dependencies = [ + "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]] +name = "secp256k1-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ - "secp256k1-sys", + "cc", ] [[package]] name = "secp256k1-sys" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -20149,6 +23945,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" @@ -20224,6 +24029,12 @@ dependencies = [ "pest", ] +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + [[package]] name = "send_wrapper" version = "0.6.0" @@ -20238,9 +24049,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", ] @@ -20275,13 +24086,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.79", + "syn 2.0.87", ] [[package]] @@ -20306,9 +24117,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.2.3", "itoa", @@ -20361,31 +24172,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.79", -] - [[package]] name = "sha-1" version = "0.9.8" @@ -20570,6 +24356,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" @@ -20654,7 +24452,7 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more", + "derive_more 0.99.17", "ed25519-zebra 4.0.3", "either", "event-listener 2.5.3", @@ -20695,34 +24493,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", @@ -20732,7 +24529,7 @@ dependencies = [ "poly1305", "rand", "rand_chacha", - "ruzstd 0.5.0", + "ruzstd 0.6.0", "schnorrkel 0.11.4", "serde", "serde_json", @@ -20741,9 +24538,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", ] @@ -20758,7 +24555,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", @@ -20786,27 +24583,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", @@ -20816,7 +24613,7 @@ dependencies = [ "siphasher 1.0.1", "slab", "smol 2.0.2", - "smoldot 0.16.0", + "smoldot 0.18.0", "zeroize", ] @@ -20858,14 +24655,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", + "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", @@ -20875,42 +24672,89 @@ 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", "rand", - "rlp", + "rlp 0.6.1", "scale-info", "serde", "serde-big-array", @@ -20921,6 +24765,27 @@ dependencies = [ "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]] name = "snowbridge-milagro-bls" version = "1.5.4" @@ -20951,83 +24816,175 @@ 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", + "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", + "alloy-sol-types", + "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]] @@ -21035,122 +24992,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]] @@ -21158,10 +25241,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]] @@ -21221,11 +25317,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", @@ -21243,17 +25339,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", ] @@ -21262,40 +25358,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]] @@ -21324,22 +25420,45 @@ dependencies = [ name = "sp-api" version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84f09c4b928e814e07dede0ece91f1f6eae1bff946a0e5e4a76bed19a095f1" +checksum = "6f84f09c4b928e814e07dede0ece91f1f6eae1bff946a0e5e4a76bed19a095f1" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "scale-info", + "sp-api-proc-macro 19.0.0", + "sp-core 33.0.1", + "sp-externalities 0.28.0", + "sp-metadata-ir 0.7.0", + "sp-runtime 37.0.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-trie 35.0.0", + "sp-version 35.0.0", + "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 19.0.0", - "sp-core 33.0.1", - "sp-externalities 0.28.0", + "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 37.0.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-trie 35.0.0", - "sp-version 35.0.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", ] @@ -21354,7 +25473,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -21369,7 +25488,22 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "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]] @@ -21408,44 +25542,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]] @@ -21468,7 +25601,7 @@ dependencies = [ "integer-sqrt", "num-traits", "parity-scale-codec", - "primitive-types", + "primitive-types 0.13.1", "rand", "scale-info", "serde", @@ -21476,21 +25609,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" @@ -21547,15 +25665,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" @@ -21582,7 +25724,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", @@ -21598,10 +25740,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]] @@ -21614,11 +25773,30 @@ 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", + "sp-inherents 26.0.0", "sp-runtime 31.0.1", - "sp-timestamp", + "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]] @@ -21635,13 +25813,35 @@ dependencies = [ "sp-crypto-hashing 0.1.0", "sp-io 30.0.0", "sp-keystore 0.34.0", - "sp-mmr-primitives", + "sp-mmr-primitives 26.0.0", "sp-runtime 31.0.1", "sp-weights 27.0.0", - "strum 0.26.2", + "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-grandpa" version = "13.0.0" @@ -21658,6 +25858,24 @@ dependencies = [ "sp-runtime 31.0.1", ] +[[package]] +name = "sp-consensus-grandpa" +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 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]] name = "sp-consensus-pow" version = "0.32.0" @@ -21668,6 +25886,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" @@ -21677,7 +25907,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", ] @@ -21689,7 +25919,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]] @@ -21708,7 +25950,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde", + "impl-serde 0.5.0", "itertools 0.11.0", "k256", "libsecp256k1", @@ -21718,13 +25960,13 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "primitive-types", + "primitive-types 0.13.1", "rand", "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", @@ -21757,7 +25999,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde", + "impl-serde 0.4.0", "itertools 0.10.5", "k256", "libsecp256k1", @@ -21767,12 +26009,12 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "primitive-types", + "primitive-types 0.12.2", "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)", @@ -21804,7 +26046,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde", + "impl-serde 0.4.0", "itertools 0.10.5", "k256", "libsecp256k1", @@ -21814,12 +26056,12 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "primitive-types", + "primitive-types 0.12.2", "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)", @@ -21851,7 +26093,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde", + "impl-serde 0.4.0", "itertools 0.11.0", "k256", "libsecp256k1", @@ -21861,12 +26103,12 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "primitive-types", + "primitive-types 0.12.2", "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)", @@ -21882,6 +26124,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" @@ -21898,6 +26187,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" @@ -21908,7 +26206,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -21945,6 +26243,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" @@ -21979,7 +26298,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.37", "sp-crypto-hashing 0.1.0", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -21990,7 +26309,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.79", + "syn 2.0.87", ] [[package]] @@ -22008,7 +26327,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -22017,7 +26336,7 @@ version = "14.0.0" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -22028,7 +26347,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -22074,6 +26393,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" @@ -22085,6 +26415,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" @@ -22098,6 +26441,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" @@ -22110,7 +26467,7 @@ dependencies = [ "parity-scale-codec", "polkavm-derive 0.9.1", "rustversion", - "secp256k1", + "secp256k1 0.28.2", "sp-core 28.0.0", "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", @@ -22125,9 +26482,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", @@ -22136,25 +26493,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", @@ -22163,43 +26520,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", ] @@ -22210,7 +26567,18 @@ version = "31.0.0" dependencies = [ "sp-core 28.0.0", "sp-runtime 31.0.1", - "strum 0.26.2", + "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]] @@ -22227,38 +26595,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]] @@ -22309,6 +26677,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" @@ -22326,6 +26706,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" @@ -22340,6 +26738,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" @@ -22347,7 +26759,7 @@ dependencies = [ "clap 4.5.13", "honggfuzz", "rand", - "sp-npos-elections", + "sp-npos-elections 26.0.0", "sp-runtime 31.0.1", ] @@ -22360,6 +26772,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" @@ -22393,7 +26816,7 @@ dependencies = [ name = "sp-runtime" version = "31.0.1" dependencies = [ - "binary-merkle-tree", + "binary-merkle-tree 13.0.0", "docify", "either", "hash256-std-hasher", @@ -22419,14 +26842,15 @@ dependencies = [ "sp-weights 27.0.0", "substrate-test-runtime-client", "tracing", + "tuplex", "zstd 0.12.4", ] [[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", @@ -22439,44 +26863,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", @@ -22490,12 +26915,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]] @@ -22506,7 +26932,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "primitive-types", + "primitive-types 0.12.2", "sp-externalities 0.19.0", "sp-runtime-interface-proc-macro 11.0.0", "sp-std 8.0.0", @@ -22524,7 +26950,7 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "polkavm-derive 0.9.1", - "primitive-types", + "primitive-types 0.13.1", "rustversion", "sp-core 28.0.0", "sp-externalities 0.25.0", @@ -22550,7 +26976,7 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "polkavm-derive 0.8.0", - "primitive-types", + "primitive-types 0.12.2", "sp-externalities 0.27.0", "sp-runtime-interface-proc-macro 18.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -22570,26 +26996,46 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "polkavm-derive 0.9.1", - "primitive-types", + "primitive-types 0.12.2", "sp-externalities 0.28.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.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#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" dependencies = [ "Inflector", "proc-macro-crate 1.3.1", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -22601,7 +27047,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -22615,7 +27061,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -22642,7 +27088,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]] @@ -22652,7 +27098,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]] @@ -22665,7 +27111,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]] @@ -22680,6 +27141,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" @@ -22701,14 +27190,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", @@ -22716,21 +27205,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", @@ -22738,20 +27226,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", @@ -22759,13 +27247,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]] @@ -22791,6 +27279,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" @@ -22811,7 +27324,7 @@ name = "sp-storage" version = "13.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ - "impl-serde", + "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", @@ -22823,7 +27336,7 @@ dependencies = [ name = "sp-storage" version = "19.0.0" dependencies = [ - "impl-serde", + "impl-serde 0.5.0", "parity-scale-codec", "ref-cast", "serde", @@ -22836,7 +27349,7 @@ version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dba5791cb3978e95daf99dad919ecb3ec35565604e88cd38d805d9d4981e8bd" dependencies = [ - "impl-serde", + "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", @@ -22850,7 +27363,7 @@ version = "21.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99c82989b3a4979a7e1ad848aad9f5d0b4388f1f454cc131766526601ab9e8f8" dependencies = [ - "impl-serde", + "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", @@ -22875,11 +27388,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" @@ -22917,14 +27443,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]] @@ -22935,6 +27461,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" @@ -22943,11 +27479,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" @@ -22969,16 +27520,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", @@ -22990,20 +27541,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", @@ -23015,19 +27565,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", @@ -23039,11 +27589,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", ] @@ -23051,31 +27601,49 @@ dependencies = [ name = "sp-version" version = "29.0.0" dependencies = [ - "impl-serde", + "impl-serde 0.5.0", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-crypto-hashing-proc-macro 0.1.0", + "sp-runtime 31.0.1", + "sp-std 14.0.0", + "sp-version-proc-macro 13.0.0", + "thiserror", +] + +[[package]] +name = "sp-version" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff74bf12b4f7d29387eb1caeec5553209a505f90a2511d2831143b970f89659" +dependencies = [ + "impl-serde 0.4.0", "parity-scale-codec", "parity-wasm", "scale-info", "serde", - "sp-crypto-hashing-proc-macro 0.1.0", - "sp-runtime 31.0.1", - "sp-std 14.0.0", - "sp-version-proc-macro 13.0.0", + "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime 37.0.0", + "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" -version = "35.0.0" +version = "37.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff74bf12b4f7d29387eb1caeec5553209a505f90a2511d2831143b970f89659" +checksum = "d521a405707b5be561367cd3d442ff67588993de24062ce3adefcf8437ee9fe1" dependencies = [ - "impl-serde", + "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 37.0.0", + "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", @@ -23090,7 +27658,7 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "sp-version 29.0.0", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -23102,7 +27670,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -23145,9 +27713,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", @@ -23170,22 +27738,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" @@ -23283,6 +27835,8 @@ name = "staging-chain-spec-builder" version = "1.6.1" dependencies = [ "clap 4.5.13", + "cmd_lib", + "docify", "log", "sc-chain-spec", "serde", @@ -23301,7 +27855,7 @@ dependencies = [ "clap_complete", "criterion", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee", "kitchensink-runtime", "log", "nix 0.28.0", @@ -23310,7 +27864,7 @@ dependencies = [ "node-testing", "parity-scale-codec", "platforms", - "polkadot-sdk", + "polkadot-sdk 0.1.0", "pretty_assertions", "rand", "regex", @@ -23319,8 +27873,10 @@ dependencies = [ "serde", "serde_json", "soketto 0.8.0", + "sp-keyring 31.0.0", "staging-node-inspect", "substrate-cli-test-utils", + "subxt-signer", "tempfile", "tokio", "tokio-util", @@ -23341,7 +27897,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", ] @@ -23349,14 +27905,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" @@ -23369,6 +27939,7 @@ dependencies = [ "bounded-collections", "derivative", "environmental", + "frame-support 28.0.0", "hex", "hex-literal", "impl-trait-for-tuples", @@ -23380,7 +27951,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]] @@ -23388,30 +27979,53 @@ 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", + "primitive-types 0.13.1", "scale-info", "sp-arithmetic 23.0.0", "sp-core 28.0.0", "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]] @@ -23419,8 +28033,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", @@ -23429,7 +28043,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", ] @@ -23446,7 +28081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" dependencies = [ "bitflags 1.3.2", - "cfg_aliases 0.1.1", + "cfg_aliases", "libc", "parking_lot 0.11.2", "parking_lot_core 0.8.6", @@ -23460,7 +28095,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ - "cfg_aliases 0.1.1", + "cfg_aliases", "memchr", "proc-macro2 1.0.86", "quote 1.0.37", @@ -23537,11 +28172,11 @@ checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros 0.26.2", + "strum_macros 0.26.4", ] [[package]] @@ -23567,20 +28202,20 @@ dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2 1.0.86", "quote 1.0.37", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -23683,9 +28318,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", @@ -23702,16 +28337,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", @@ -23740,39 +28375,39 @@ 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", "structopt", - "strum 0.26.2", + "strum 0.26.3", "thiserror", ] @@ -23781,7 +28416,7 @@ name = "substrate-rpc-client" version = "0.33.0" dependencies = [ "async-trait", - "jsonrpsee 0.24.3", + "jsonrpsee", "log", "sc-rpc-api", "serde", @@ -23802,7 +28437,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", ] @@ -23810,7 +28445,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", @@ -23820,7 +28455,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]] @@ -23842,7 +28477,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", @@ -23854,16 +28489,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", @@ -23875,30 +28510,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]] @@ -23923,6 +28558,7 @@ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ "futures", + "log", "parity-scale-codec", "parking_lot 0.12.3", "sc-transaction-pool", @@ -23965,7 +28601,28 @@ dependencies = [ "sp-maybe-compressed-blob 11.0.0", "sp-tracing 16.0.0", "sp-version 29.0.0", - "strum 0.26.2", + "strum 0.26.3", + "tempfile", + "toml 0.8.12", + "walkdir", + "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", @@ -24018,101 +28675,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", - "instant", - "jsonrpsee 0.22.5", + "impl-serde 0.5.0", + "jsonrpsee", "parity-scale-codec", - "primitive-types", - "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.79", + "syn 2.0.87", "thiserror", - "tokio", ] [[package]] name = "subxt-core" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f41eb2e2eea6ed45649508cc735f92c27f1fcfb15229e75f8270ea73177345" +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", + "impl-serde 0.5.0", + "keccak-hash", "parity-scale-codec", - "primitive-types", + "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", @@ -24121,54 +28776,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.79", + "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" @@ -24284,9 +28959,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", @@ -24302,7 +28977,7 @@ dependencies = [ "paste", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -24331,7 +29006,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -24402,7 +29077,7 @@ dependencies = [ "cfg-if", "fastrand 2.1.0", "redox_syscall 0.4.1", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -24432,7 +29107,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -24461,7 +29136,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -24470,9 +29145,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", ] @@ -24489,14 +29164,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", @@ -24507,7 +29182,7 @@ name = "test-parachain-halt" version = "1.0.0" dependencies = [ "rustversion", - "substrate-wasm-builder", + "substrate-wasm-builder 17.0.0", ] [[package]] @@ -24517,9 +29192,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", ] @@ -24536,14 +29211,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", @@ -24564,8 +29239,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", ] @@ -24574,14 +29249,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]] @@ -24601,9 +29292,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] @@ -24630,13 +29321,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -24798,7 +29489,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -24832,24 +29523,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.10", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] @@ -24868,9 +29548,9 @@ dependencies = [ [[package]] name = "tokio-test" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b3cbabd3ae862100094ae433e1def582cf86451b4e9bf83aa7ac1d8a7d719" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" dependencies = [ "async-stream", "bytes", @@ -24896,9 +29576,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", @@ -25074,7 +29754,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -25102,7 +29782,7 @@ name = "tracing-gum" version = "7.0.0" dependencies = [ "coarsetime", - "polkadot-primitives", + "polkadot-primitives 7.0.0", "tracing", "tracing-gum-proc-macro", ] @@ -25116,7 +29796,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -25205,24 +29885,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" @@ -25438,6 +30105,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unarray" version = "0.1.4" @@ -25561,7 +30240,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "serde", "serde_json", @@ -25734,9 +30413,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", @@ -25747,24 +30426,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.79", + "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", @@ -25774,9 +30453,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", @@ -25784,22 +30463,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.79", + "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" @@ -25919,7 +30598,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", @@ -26256,6 +30935,16 @@ 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" @@ -26286,95 +30975,97 @@ 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]] name = "westend-runtime" version = "7.0.0" dependencies = [ - "binary-merkle-tree", + "approx", + "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-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", @@ -26383,49 +31074,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]] @@ -26515,7 +31223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core 0.52.0", - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -26533,7 +31241,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -26560,7 +31268,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -26595,17 +31312,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -26622,9 +31340,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -26640,9 +31358,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -26658,9 +31376,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -26676,9 +31400,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -26694,9 +31418,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -26712,9 +31436,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -26730,9 +31454,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -26841,24 +31565,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]] @@ -26866,23 +31590,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", @@ -26890,30 +31614,30 @@ 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", "futures", - "pallet-transaction-payment", - "pallet-xcm", + "pallet-transaction-payment 28.0.0", + "pallet-xcm 7.0.0", "parity-scale-codec", "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]] @@ -26923,80 +31647,130 @@ dependencies = [ "Inflector", "proc-macro2 1.0.86", "quote 1.0.37", - "staging-xcm", - "syn 2.0.79", + "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]] @@ -27004,27 +31778,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]] @@ -27095,7 +31869,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -27115,7 +31889,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -27136,9 +31910,9 @@ dependencies = [ [[package]] name = "zombienet-configuration" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbfc98adb25076777967f7aad078e74029e129b102eb0812c425432f8c2be7b" +checksum = "7d7a8cc4f8e8bb3f40757b62d3b054da5c95f43321c775eb321edc89d431583e" dependencies = [ "anyhow", "lazy_static", @@ -27156,9 +31930,9 @@ dependencies = [ [[package]] name = "zombienet-orchestrator" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b17f4d1d05b3aedf02818eb0f4d5a76664da0e07bb2f7e7d02613e0ef0f316a" +checksum = "3d32fa87851f41443a78971bd7110274f9a66d139ac834de159adc08f90cf8e3" dependencies = [ "anyhow", "async-trait", @@ -27189,9 +31963,9 @@ dependencies = [ [[package]] name = "zombienet-prom-metrics-parser" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7203390ab88919240da3a3eb06b625b6e300e94f98e04ba5141e9138dc663b7d" +checksum = "9acb9c94bc7c2c83f8eb8e26ed403f757af1632f22b89394d8876412ede990ca" dependencies = [ "pest", "pest_derive", @@ -27200,9 +31974,9 @@ dependencies = [ [[package]] name = "zombienet-provider" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee02ee957ec39b698798fa6dc2a0d5ba4524198471c37d57755e9685b67fb50c" +checksum = "dc8f3f71d4d974fc4a2262fa9293c2eedc423540378bd7c1dc1b66cc95d1d1af" dependencies = [ "anyhow", "async-trait", @@ -27231,9 +32005,9 @@ dependencies = [ [[package]] name = "zombienet-sdk" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f594e67922182277a3da0926f21b693eb5a0c38b32ca7fd6ef16167809fe5064" +checksum = "5dbfddce7a6100cdc930b93301f1b6381e6577ecc013d6802258ea6902a2bebd" dependencies = [ "async-trait", "futures", @@ -27248,9 +32022,9 @@ dependencies = [ [[package]] name = "zombienet-support" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d3144537df7c8939bbb355cc5245a6dc0078446a6cdaf9272268bd1043c788" +checksum = "d20567c52b4fd46b600cda254dedb6a6dc30cabf512de91e4f6f78f0f7f4644b" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index df662ac26988..533ea4c9e878 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -133,8 +133,9 @@ members = [ "cumulus/parachains/runtimes/test-utils", "cumulus/parachains/runtimes/testing/penpal", "cumulus/parachains/runtimes/testing/rococo-parachain", + "cumulus/polkadot-omni-node", + "cumulus/polkadot-omni-node/lib", "cumulus/polkadot-parachain", - "cumulus/polkadot-parachain/polkadot-parachain-lib", "cumulus/primitives/aura", "cumulus/primitives/core", "cumulus/primitives/parachain-inherent", @@ -148,6 +149,8 @@ members = [ "cumulus/test/service", "cumulus/xcm/xcm-emulator", "docs/sdk", + "docs/sdk/packages/guides/first-pallet", + "docs/sdk/packages/guides/first-runtime", "docs/sdk/src/reference_docs/chain_spec_runtime", "polkadot", "polkadot/cli", @@ -346,6 +349,7 @@ members = [ "substrate/frame/election-provider-support/solution-type/fuzzer", "substrate/frame/elections-phragmen", "substrate/frame/examples", + "substrate/frame/examples/authorization-tx-extension", "substrate/frame/examples/basic", "substrate/frame/examples/default-config", "substrate/frame/examples/dev-mode", @@ -398,6 +402,7 @@ members = [ "substrate/frame/revive/fixtures", "substrate/frame/revive/mock-network", "substrate/frame/revive/proc-macro", + "substrate/frame/revive/rpc", "substrate/frame/revive/uapi", "substrate/frame/root-offences", "substrate/frame/root-testing", @@ -441,6 +446,7 @@ members = [ "substrate/frame/tx-pause", "substrate/frame/uniques", "substrate/frame/utility", + "substrate/frame/verify-signature", "substrate/frame/vesting", "substrate/frame/whitelist", "substrate/primitives/api", @@ -541,6 +547,7 @@ members = [ ] default-members = [ + "cumulus/polkadot-omni-node", "cumulus/polkadot-parachain", "polkadot", "substrate/bin/node/cli", @@ -549,7 +556,13 @@ default-members = [ [workspace.lints.rust] suspicious_double_ref_op = { level = "allow", priority = 2 } # `substrate_runtime` is a common `cfg` condition name used in the repo. -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(build_opt_level, values("3"))', 'cfg(build_profile, values("debug", "release"))', 'cfg(enable_alloc_error_handler)', 'cfg(fuzzing)', 'cfg(substrate_runtime)'] } +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(build_opt_level, values("3"))', + 'cfg(build_profile, values("debug", "release"))', + 'cfg(enable_alloc_error_handler)', + 'cfg(fuzzing)', + 'cfg(substrate_runtime)', +] } [workspace.lints.clippy] all = { level = "allow", priority = 0 } @@ -585,6 +598,7 @@ alloy-primitives = { version = "0.4.2", default-features = false } alloy-sol-types = { version = "0.4.2", default-features = false } always-assert = { version = "0.1" } anyhow = { version = "1.0.81", default-features = false } +approx = { version = "0.5.1" } aquamarine = { version = "0.5.0" } arbitrary = { version = "1.3.2" } ark-bls12-377 = { version = "0.4.0", default-features = false } @@ -623,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 } @@ -669,6 +683,7 @@ cid = { version = "0.9.0" } clap = { version = "4.5.13" } clap-num = { version = "1.0.2" } clap_complete = { version = "4.5.13" } +cmd_lib = { version = "1.9.5" } coarsetime = { version = "0.1.22" } codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" } collectives-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend" } @@ -678,6 +693,7 @@ color-print = { version = "0.3.4" } colored = { version = "2.0.4" } comfy-table = { version = "7.1.0", default-features = false } console = { version = "0.15.8" } +const-hex = { version = "1.10.0", default-features = false } contracts-rococo-runtime = { path = "cumulus/parachains/runtimes/contracts/contracts-rococo" } coretime-rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo" } coretime-rococo-runtime = { path = "cumulus/parachains/runtimes/coretime/coretime-rococo" } @@ -726,7 +742,7 @@ derive_more = { version = "0.99.17", default-features = false } digest = { version = "0.10.3", default-features = false } directories = { version = "5.0.1" } dlmalloc = { version = "0.2.4" } -docify = { version = "0.2.8" } +docify = { version = "0.2.9" } dyn-clonable = { version = "0.9.0" } dyn-clone = { version = "1.0.16" } ed25519-dalek = { version = "2.1", default-features = false } @@ -738,9 +754,9 @@ 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" } -ethbloom = { version = "0.13.0", default-features = false } -ethereum-types = { version = "0.14.1", default-features = false } +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" } expander = { version = "2.0.0" } fatality = { version = "0.1.1" } @@ -749,6 +765,8 @@ femme = { version = "2.2.1" } filetime = { version = "0.2.16" } finality-grandpa = { version = "0.16.2", default-features = false } finality-relay = { path = "bridges/relays/finality" } +first-pallet = { package = "polkadot-sdk-docs-first-pallet", path = "docs/sdk/packages/guides/first-pallet", default-features = false } +first-runtime = { package = "polkadot-sdk-docs-first-runtime", path = "docs/sdk/packages/guides/first-runtime", default-features = false } flate2 = { version = "1.0" } fnv = { version = "1.0.6" } fork-tree = { path = "substrate/utils/fork-tree", default-features = false } @@ -774,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 } @@ -797,11 +815,9 @@ http = { version = "1.1" } http-body = { version = "1", default-features = false } http-body-util = { version = "0.1.2", default-features = false } hyper = { version = "1.3.1", default-features = false } -hyper-rustls = { version = "0.24.2" } +hyper-rustls = { version = "0.27.3", default-features = false, features = ["http1", "http2", "logging", "ring", "rustls-native-certs", "tls12"] } hyper-util = { version = "0.1.5", default-features = false } -# TODO: remove hyper v0.14 https://github.com/paritytech/polkadot-sdk/issues/4896 -hyperv14 = { package = "hyper", version = "0.14.29", default-features = false } -impl-serde = { version = "0.4.0", default-features = false } +impl-serde = { version = "0.5.0", default-features = false } impl-trait-for-tuples = { version = "0.2.2" } indexmap = { version = "2.0.0" } indicatif = { version = "0.17.7" } @@ -832,7 +848,7 @@ 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.1", features = ["websocket"] } log = { version = "0.4.22", default-features = false } macro_magic = { version = "0.5.1" } maplit = { version = "1.0.2" } @@ -912,6 +928,7 @@ pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } +pallet-example-authorization-tx-extension = { path = "substrate/frame/examples/authorization-tx-extension", default-features = false } pallet-example-basic = { path = "substrate/frame/examples/basic", default-features = false } pallet-example-frame-crate = { path = "substrate/frame/examples/frame-crate", default-features = false } pallet-example-kitchensink = { path = "substrate/frame/examples/kitchensink", default-features = false } @@ -956,6 +973,7 @@ pallet-recovery = { path = "substrate/frame/recovery", default-features = false pallet-referenda = { path = "substrate/frame/referenda", default-features = false } pallet-remark = { default-features = false, path = "substrate/frame/remark" } pallet-revive = { path = "substrate/frame/revive", default-features = false } +pallet-revive-eth-rpc = { path = "substrate/frame/revive/rpc", default-features = false } pallet-revive-fixtures = { path = "substrate/frame/revive/fixtures", default-features = false } pallet-revive-mock-network = { default-features = false, path = "substrate/frame/revive/mock-network" } pallet-revive-proc-macro = { path = "substrate/frame/revive/proc-macro", default-features = false } @@ -988,6 +1006,7 @@ pallet-treasury = { path = "substrate/frame/treasury", default-features = false pallet-tx-pause = { default-features = false, path = "substrate/frame/tx-pause" } pallet-uniques = { path = "substrate/frame/uniques", default-features = false } pallet-utility = { path = "substrate/frame/utility", default-features = false } +pallet-verify-signature = { path = "substrate/frame/verify-signature", default-features = false } pallet-vesting = { path = "substrate/frame/vesting", default-features = false } pallet-whitelist = { path = "substrate/frame/whitelist", default-features = false } pallet-xcm = { path = "polkadot/xcm/pallet-xcm", default-features = false } @@ -1001,7 +1020,6 @@ parachains-relay = { path = "bridges/relays/parachains" } parachains-runtimes-test-utils = { path = "cumulus/parachains/runtimes/test-utils", default-features = false } parity-bytes = { version = "0.1.2", default-features = false } parity-db = { version = "0.4.12" } -parity-util-mem = { version = "0.12.0" } parity-wasm = { version = "0.45.0" } parking_lot = { version = "0.12.1", default-features = false } partial_sort = { version = "0.2.0" } @@ -1014,7 +1032,7 @@ people-rococo-runtime = { path = "cumulus/parachains/runtimes/people/people-roco people-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend" } people-westend-runtime = { path = "cumulus/parachains/runtimes/people/people-westend" } pin-project = { version = "1.1.3" } -platforms = { version = "3.0" } +platforms = { version = "3.4" } polkadot-approval-distribution = { path = "polkadot/node/network/approval-distribution", default-features = false } polkadot-availability-bitfield-distribution = { path = "polkadot/node/network/bitfield-distribution", default-features = false } polkadot-availability-distribution = { path = "polkadot/node/network/availability-distribution", default-features = false } @@ -1052,8 +1070,9 @@ polkadot-node-subsystem = { path = "polkadot/node/subsystem", default-features = polkadot-node-subsystem-test-helpers = { path = "polkadot/node/subsystem-test-helpers" } polkadot-node-subsystem-types = { path = "polkadot/node/subsystem-types", default-features = false } polkadot-node-subsystem-util = { path = "polkadot/node/subsystem-util", default-features = false } +polkadot-omni-node = { path = "cumulus/polkadot-omni-node", default-features = false } +polkadot-omni-node-lib = { path = "cumulus/polkadot-omni-node/lib", default-features = false } polkadot-overseer = { path = "polkadot/node/overseer", default-features = false } -polkadot-parachain-lib = { path = "cumulus/polkadot-parachain/polkadot-parachain-lib", default-features = false } polkadot-parachain-primitives = { path = "polkadot/parachain", default-features = false } polkadot-primitives = { path = "polkadot/primitives", default-features = false } polkadot-primitives-test-helpers = { path = "polkadot/primitives/test-helpers" } @@ -1075,7 +1094,9 @@ polkavm-derive = "0.9.1" polkavm-linker = "0.9.2" portpicker = { version = "0.1.1" } pretty_assertions = { version = "1.3.0" } -primitive-types = { version = "0.12.1", default-features = false } +primitive-types = { version = "0.13.1", default-features = false, features = [ + "num-traits", +] } proc-macro-crate = { version = "3.0.0" } proc-macro-warning = { version = "1.0.0", default-features = false } proc-macro2 = { version = "1.0.86" } @@ -1084,7 +1105,7 @@ prometheus = { version = "0.13.0", default-features = false } prometheus-endpoint = { path = "substrate/utils/prometheus", default-features = false, package = "substrate-prometheus-endpoint" } prometheus-parse = { version = "0.2.2" } prost = { version = "0.12.4" } -prost-build = { version = "0.12.4" } +prost-build = { version = "0.13.2" } pyroscope = { version = "0.5.7" } pyroscope_pprofrs = { version = "0.2.7" } quick_cache = { version = "0.3" } @@ -1103,7 +1124,7 @@ 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 } -rlp = { version = "0.5.2", 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" } rococo-runtime = { path = "polkadot/runtime/rococo" } @@ -1115,6 +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"] } rustversion = { version = "1.0.17" } rusty-fork = { version = "0.3.0", default-features = false } safe-mix = { version = "1.0", default-features = false } @@ -1183,12 +1205,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.128", default-features = false } +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 } @@ -1280,7 +1301,7 @@ ssz_rs_derive = { version = "0.9.0", default-features = false } static_assertions = { version = "1.1.0", default-features = false } static_init = { version = "1.0.3" } structopt = { version = "0.3" } -strum = { version = "0.26.2", default-features = false } +strum = { version = "0.26.3", default-features = false } subkey = { path = "substrate/bin/utils/subkey", default-features = false } substrate-bip39 = { path = "substrate/utils/substrate-bip39", default-features = false } substrate-build-script-utils = { path = "substrate/utils/build-script-utils", default-features = false } @@ -1295,9 +1316,9 @@ substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } substrate-test-utils = { path = "substrate/test-utils" } substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } -subxt = { version = "0.37", default-features = false } -subxt-signer = { version = "0.37" } -syn = { version = "2.0.79" } +subxt = { version = "0.38", 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" } @@ -1308,7 +1329,7 @@ test-parachain-halt = { path = "polkadot/parachain/test-parachains/halt" } test-parachain-undying = { path = "polkadot/parachain/test-parachains/undying" } test-runtime-constants = { path = "polkadot/runtime/test-runtime/constants", default-features = false } testnet-parachains-constants = { path = "cumulus/parachains/runtimes/constants", default-features = false } -thiserror = { version = "1.0.48" } +thiserror = { version = "1.0.64" } thousands = { version = "0.2.0" } threadpool = { version = "1.7" } tikv-jemalloc-ctl = { version = "0.5.0" } @@ -1318,7 +1339,7 @@ tiny-keccak = { version = "2.0.2" } tokio = { version = "1.40.0", default-features = false } tokio-retry = { version = "0.3.0" } tokio-stream = { version = "0.1.14" } -tokio-test = { version = "0.4.2" } +tokio-test = { version = "0.4.4" } tokio-tungstenite = { version = "0.20.1" } tokio-util = { version = "0.7.8" } toml = { version = "0.8.12" } @@ -1366,7 +1387,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.15" } zstd = { version = "0.12.4", default-features = false } [profile.release] diff --git a/README.md b/README.md index b8ddf8427c9f..6c0dfbb2e7e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -
![SDK Logo](./docs/images/Polkadot_Logo_Horizontal_Pink_White.png#gh-dark-mode-only) @@ -20,6 +19,7 @@ forks](https://img.shields.io/github/forks/paritytech/polkadot-sdk) ## ⚡ Quickstart If you want to get an example node running quickly you can execute the following getting started script: + ``` curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/scripts/getting-started.sh | bash ``` @@ -32,9 +32,8 @@ curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/paritytec * [Guides](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/index.html), namely how to build your first FRAME pallet * [Templates](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/templates/index.html) - for starting a new project -* Other resources: - * [Polkadot Wiki -> Build](https://wiki.polkadot.network/docs/build-guide) + for starting a new project. + * [External Resources](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/external_resources/index.html) ## 🚀 Releases diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index b8835d55f0da..37b56140c289 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -39,6 +39,7 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } sp-trie = { optional = true, workspace = true } +sp-weights = { workspace = true } # Polkadot dependencies xcm = { workspace = true } @@ -80,6 +81,7 @@ std = [ "sp-runtime/std", "sp-std/std", "sp-trie/std", + "sp-weights/std", "tuplex/std", "xcm/std", ] @@ -93,6 +95,7 @@ runtime-benchmarks = [ "pallet-bridge-messages/test-helpers", "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-trie", diff --git a/bridges/bin/runtime-common/src/extensions.rs b/bridges/bin/runtime-common/src/extensions.rs index dced50239471..44e6b40b7e0c 100644 --- a/bridges/bin/runtime-common/src/extensions.rs +++ b/bridges/bin/runtime-common/src/extensions.rs @@ -47,8 +47,7 @@ pub trait BridgeRuntimeFilterCall { /// Data that may be passed from the validate to `post_dispatch`. type ToPostDispatch; /// Called during validation. Needs to checks whether a runtime call, submitted - /// by the `who` is valid. `who` may be `None` if transaction is not signed - /// by a regular account. + /// by the `who` is valid. Transactions not signed are not validated. fn validate(who: &AccountId, call: &Call) -> (Self::ToPostDispatch, TransactionValidity); /// Called after transaction is dispatched. fn post_dispatch(_who: &AccountId, _has_failed: bool, _to_post_dispatch: Self::ToPostDispatch) { @@ -274,12 +273,10 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { ($call:ty, $account_id:ty, $($filter_call:ty),*) => { #[derive(Clone, codec::Decode, Default, codec::Encode, Eq, PartialEq, sp_runtime::RuntimeDebug, scale_info::TypeInfo)] pub struct BridgeRejectObsoleteHeadersAndMessages; - impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteHeadersAndMessages { + impl sp_runtime::traits::TransactionExtension<$call> for BridgeRejectObsoleteHeadersAndMessages { const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; - type AccountId = $account_id; - type Call = $call; - type AdditionalSigned = (); - type Pre = ( + type Implicit = (); + type Val = Option<( $account_id, ( $( <$filter_call as $crate::extensions::BridgeRuntimeFilterCall< @@ -287,72 +284,76 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { $call, >>::ToPostDispatch, )* ), - ); + )>; + type Pre = Self::Val; - fn additional_signed(&self) -> sp_std::result::Result< - (), - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(()) + fn weight(&self, _: &$call) -> frame_support::pallet_prelude::Weight { + frame_support::pallet_prelude::Weight::zero() } - #[allow(unused_variables)] fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, + origin: <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + call: &$call, + _info: &sp_runtime::traits::DispatchInfoOf<$call>, _len: usize, - ) -> sp_runtime::transaction_validity::TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl codec::Encode, + _source: sp_runtime::transaction_validity::TransactionSource, + ) -> Result< + ( + sp_runtime::transaction_validity::ValidTransaction, + Self::Val, + <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + ), sp_runtime::transaction_validity::TransactionValidityError + > { + use $crate::extensions::__private::tuplex::PushBack; + use sp_runtime::traits::AsSystemOriginSigner; + + let Some(who) = origin.as_system_origin_signer() else { + return Ok((Default::default(), None, origin)); + }; + + let to_post_dispatch = (); let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default(); - let to_prepare = (); $( let (from_validate, call_filter_validity) = < $filter_call as $crate::extensions::BridgeRuntimeFilterCall< - Self::AccountId, + $account_id, $call, - >>::validate(&who, call); + >>::validate(who, call); + let to_post_dispatch = to_post_dispatch.push_back(from_validate); let tx_validity = tx_validity.combine_with(call_filter_validity?); )* - Ok(tx_validity) + Ok((tx_validity, Some((who.clone(), to_post_dispatch)), origin)) } - #[allow(unused_variables)] - fn pre_dispatch( + fn prepare( self, - relayer: &Self::AccountId, - call: &Self::Call, - info: &sp_runtime::traits::DispatchInfoOf, - len: usize, + val: Self::Val, + _origin: &<$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + _call: &$call, + _info: &sp_runtime::traits::DispatchInfoOf<$call>, + _len: usize, ) -> Result { - use $crate::extensions::__private::tuplex::PushBack; - - let to_post_dispatch = (); - $( - let (from_validate, call_filter_validity) = < - $filter_call as - $crate::extensions::BridgeRuntimeFilterCall< - $account_id, - $call, - >>::validate(&relayer, call); - let _ = call_filter_validity?; - let to_post_dispatch = to_post_dispatch.push_back(from_validate); - )* - Ok((relayer.clone(), to_post_dispatch)) + Ok(val) } #[allow(unused_variables)] - fn post_dispatch( - to_post_dispatch: Option, - info: &sp_runtime::traits::DispatchInfoOf, - post_info: &sp_runtime::traits::PostDispatchInfoOf, + fn post_dispatch_details( + to_post_dispatch: Self::Pre, + info: &sp_runtime::traits::DispatchInfoOf<$call>, + post_info: &sp_runtime::traits::PostDispatchInfoOf<$call>, len: usize, result: &sp_runtime::DispatchResult, - ) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> { + ) -> Result { use $crate::extensions::__private::tuplex::PopFront; - let Some((relayer, to_post_dispatch)) = to_post_dispatch else { return Ok(()) }; + let Some((relayer, to_post_dispatch)) = to_post_dispatch else { + return Ok(frame_support::pallet_prelude::Weight::zero()) + }; + let has_failed = result.is_err(); $( let (item, to_post_dispatch) = to_post_dispatch.pop_front(); @@ -363,7 +364,7 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { $call, >>::post_dispatch(&relayer, has_failed, item); )* - Ok(()) + Ok(frame_support::pallet_prelude::Weight::zero()) } } }; @@ -380,12 +381,19 @@ mod tests { use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::HeaderId; use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID}; + use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{assert_err, assert_ok, traits::fungible::Mutate}; use pallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet}; use pallet_bridge_parachains::Call as ParachainsCall; + use scale_info::TypeInfo; use sp_runtime::{ - traits::{parameter_types, ConstU64, Header as _, SignedExtension}, - transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + traits::{ + parameter_types, AsSystemOriginSigner, AsTransactionAuthorizedOrigin, ConstU64, + DispatchTransaction, Header as _, TransactionExtension, + }, + transaction_validity::{ + InvalidTransaction, TransactionSource::External, TransactionValidity, ValidTransaction, + }, DispatchError, }; @@ -402,12 +410,34 @@ mod tests { ); } + #[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct MockCall { data: u32, } + #[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] + pub struct MockOrigin(pub u64); + + impl AsSystemOriginSigner for MockOrigin { + fn as_system_origin_signer(&self) -> Option<&u64> { + Some(&self.0) + } + } + + impl AsTransactionAuthorizedOrigin for MockOrigin { + fn is_transaction_authorized(&self) -> bool { + true + } + } + + impl From for MockOrigin { + fn from(o: u64) -> Self { + Self(o) + } + } + impl sp_runtime::traits::Dispatchable for MockCall { - type RuntimeOrigin = u64; + type RuntimeOrigin = MockOrigin; type Config = (); type Info = (); type PostInfo = (); @@ -579,66 +609,85 @@ mod tests { run_test(|| { assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&42, &MockCall { data: 1 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate_only( + 42u64.into(), + &MockCall { data: 1 }, + &(), + 0, + External, + 0, + ), InvalidTransaction::Custom(1) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.pre_dispatch( - &42, + BridgeRejectObsoleteHeadersAndMessages.validate_and_prepare( + 42u64.into(), &MockCall { data: 1 }, &(), - 0 + 0, + 0, ), InvalidTransaction::Custom(1) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&42, &MockCall { data: 2 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate_only( + 42u64.into(), + &MockCall { data: 2 }, + &(), + 0, + External, + 0, + ), InvalidTransaction::Custom(2) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.pre_dispatch( - &42, + BridgeRejectObsoleteHeadersAndMessages.validate_and_prepare( + 42u64.into(), &MockCall { data: 2 }, &(), - 0 + 0, + 0, ), InvalidTransaction::Custom(2) ); assert_eq!( BridgeRejectObsoleteHeadersAndMessages - .validate(&42, &MockCall { data: 3 }, &(), 0) - .unwrap(), + .validate_only(42u64.into(), &MockCall { data: 3 }, &(), 0, External, 0) + .unwrap() + .0, ValidTransaction { priority: 3, ..Default::default() }, ); assert_eq!( BridgeRejectObsoleteHeadersAndMessages - .pre_dispatch(&42, &MockCall { data: 3 }, &(), 0) + .validate_and_prepare(42u64.into(), &MockCall { data: 3 }, &(), 0, 0) + .unwrap() + .0 .unwrap(), (42, (1, 2)), ); // when post_dispatch is called with `Ok(())`, it is propagated to all "nested" // extensions - assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch( + assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch_details( Some((0, (1, 2))), &(), &(), 0, - &Ok(()) + &Ok(()), )); FirstFilterCall::verify_post_dispatch_called_with(true); SecondFilterCall::verify_post_dispatch_called_with(true); // when post_dispatch is called with `Err(())`, it is propagated to all "nested" // extensions - assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch( + assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch_details( Some((0, (1, 2))), &(), &(), 0, - &Err(DispatchError::BadOrigin) + &Err(DispatchError::BadOrigin), )); FirstFilterCall::verify_post_dispatch_called_with(false); SecondFilterCall::verify_post_dispatch_called_with(false); diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 1d4043fc4b61..6cf04b452da7 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -162,7 +162,6 @@ impl pallet_transaction_payment::Config for TestRuntime { MinimumMultiplier, MaximumMultiplier, >; - type RuntimeEvent = RuntimeEvent; } impl pallet_bridge_grandpa::Config for TestRuntime { diff --git a/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs index a5c90ceba111..f626fa6df010 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs @@ -26,7 +26,7 @@ pub use bp_polkadot_core::{ }; use bp_messages::*; -use bp_polkadot_core::SuffixedCommonSignedExtension; +use bp_polkadot_core::SuffixedCommonTransactionExtension; use bp_runtime::extensions::{ BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, }; @@ -167,7 +167,7 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// Signed extension that is used by all bridge hubs. -pub type SignedExtension = SuffixedCommonSignedExtension<( +pub type TransactionExtension = SuffixedCommonTransactionExtension<( BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, )>; diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index 538bc44019f5..fda6a5f0b722 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -109,11 +109,11 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) - pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 297_644_174; + pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 297_685_840; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) - pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 56_740_432; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 56_782_099; } /// Wrapper over `BridgeHubRococo`'s `RuntimeCall` that can be used without a runtime. diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 7a213fdb28c8..e941b5840238 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -98,11 +98,11 @@ frame_support::parameter_types! { /// Transaction fee that is paid at the Westend BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) - pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 89_293_427_116; + pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 89_305_927_116; /// Transaction fee that is paid at the Westend BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) - pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_022_177_116; + pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_034_677_116; } /// Wrapper over `BridgeHubWestend`'s `RuntimeCall` that can be used without a runtime. diff --git a/bridges/chains/chain-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs index dcd0b23abbbe..f1f30c4484eb 100644 --- a/bridges/chains/chain-kusama/src/lib.rs +++ b/bridges/chains/chain-kusama/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Kusama { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The SignedExtension used by Kusama. -pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; +// The TransactionExtension used by Kusama. +pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; /// Name of the parachains pallet in the Kusama runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/chains/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index d00936919721..c5c18beb2cad 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, extensions::{ CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, - CheckWeight, GenericSignedExtension, GenericSignedExtensionSchema, + CheckWeight, GenericTransactionExtension, GenericTransactionExtensionSchema, }, Chain, ChainId, TransactionEra, }; @@ -38,7 +38,8 @@ use frame_support::{ use frame_system::limits; use scale_info::TypeInfo; use sp_runtime::{ - traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill, StateVersion, + impl_tx_ext_default, traits::Dispatchable, transaction_validity::TransactionValidityError, + Perbill, StateVersion, }; // This chain reuses most of Polkadot primitives. @@ -73,10 +74,10 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// This signed extension is used to ensure that the chain transactions are signed by proper -pub type ValidateSigned = GenericSignedExtensionSchema<(), ()>; +pub type ValidateSigned = GenericTransactionExtensionSchema<(), ()>; /// Signed extension schema, used by Polkadot Bulletin. -pub type SignedExtensionSchema = GenericSignedExtension<( +pub type TransactionExtensionSchema = GenericTransactionExtension<( ( CheckNonZeroSender, CheckSpecVersion, @@ -89,34 +90,30 @@ pub type SignedExtensionSchema = GenericSignedExtension<( ValidateSigned, )>; -/// Signed extension, used by Polkadot Bulletin. +/// Transaction extension, used by Polkadot Bulletin. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct SignedExtension(SignedExtensionSchema); +pub struct TransactionExtension(TransactionExtensionSchema); -impl sp_runtime::traits::SignedExtension for SignedExtension { +impl sp_runtime::traits::TransactionExtension for TransactionExtension +where + C: Dispatchable, +{ const IDENTIFIER: &'static str = "Not needed."; - type AccountId = (); - type Call = (); - type AdditionalSigned = - ::AdditionalSigned; - type Pre = (); + type Implicit = + >::Implicit; - fn additional_signed(&self) -> Result { - self.0.additional_signed() + fn implicit(&self) -> Result { + >::implicit( + &self.0, + ) } + type Pre = (); + type Val = (); - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } + impl_tx_ext_default!(C; weight validate prepare); } -impl SignedExtension { +impl TransactionExtension { /// Create signed extension from its components. pub fn from_params( spec_version: u32, @@ -125,7 +122,7 @@ impl SignedExtension { genesis_hash: Hash, nonce: Nonce, ) -> Self { - Self(GenericSignedExtension::new( + Self(GenericTransactionExtension::new( ( ( (), // non-zero sender diff --git a/bridges/chains/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs index f4b262d40735..5d2f9e4aa9e0 100644 --- a/bridges/chains/chain-polkadot/src/lib.rs +++ b/bridges/chains/chain-polkadot/src/lib.rs @@ -63,8 +63,8 @@ impl ChainWithGrandpa for Polkadot { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -/// The SignedExtension used by Polkadot. -pub type SignedExtension = SuffixedCommonSignedExtension; +/// The TransactionExtension used by Polkadot. +pub type TransactionExtension = SuffixedCommonTransactionExtension; /// Name of the parachains pallet in the Polkadot runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/chains/chain-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs index bfcafdf41ea2..2827d1f137b0 100644 --- a/bridges/chains/chain-rococo/src/lib.rs +++ b/bridges/chains/chain-rococo/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Rococo { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The SignedExtension used by Rococo. -pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; +// The TransactionExtension used by Rococo. +pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/chains/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs index 2a247e03e59d..2b0a609115bc 100644 --- a/bridges/chains/chain-westend/src/lib.rs +++ b/bridges/chains/chain-westend/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Westend { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The SignedExtension used by Westend. -pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; +// The TransactionExtension used by Westend. +pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 0bf889bcca0e..04e7b52ed86c 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -79,6 +79,7 @@ runtime-benchmarks = [ "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", "pallet-bridge-parachains/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/bridges/modules/relayers/src/extension/mod.rs b/bridges/modules/relayers/src/extension/mod.rs index 9a248eb8e798..34d280d26d6e 100644 --- a/bridges/modules/relayers/src/extension/mod.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -33,6 +33,8 @@ 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, }; use frame_system::Config as SystemConfig; @@ -44,10 +46,11 @@ use pallet_transaction_payment::{ }; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{ - TransactionValidity, TransactionValidityError, ValidTransactionBuilder, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, + TransactionExtension, ValidateResult, Zero, }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransactionBuilder}, DispatchResult, RuntimeDebug, }; use sp_std::{fmt::Debug, marker::PhantomData}; @@ -62,7 +65,7 @@ mod messages_adapter; mod parachain_adapter; mod priority; -/// Data that is crafted in `pre_dispatch` method and used at `post_dispatch`. +/// Data that is crafted in `validate`, passed to `prepare` and used at `post_dispatch` method. #[cfg_attr(test, derive(Debug, PartialEq))] pub struct PreDispatchData< AccountId, @@ -78,7 +81,7 @@ pub struct PreDispatchData< impl PreDispatchData { - /// Returns mutable reference to pre-dispatch `finality_target` sent to the + /// Returns mutable reference to `finality_target` sent to the /// `SubmitFinalityProof` call. #[cfg(test)] pub fn submit_finality_proof_info_mut( @@ -119,11 +122,11 @@ pub enum RelayerAccountAction { TypeInfo, )] #[scale_info(skip_type_params(Runtime, Config, LaneId))] -pub struct BridgeRelayersSignedExtension( +pub struct BridgeRelayersTransactionExtension( PhantomData<(Runtime, Config, LaneId)>, ); -impl BridgeRelayersSignedExtension +impl BridgeRelayersTransactionExtension where Self: 'static + Send + Sync, R: RelayersConfig @@ -131,6 +134,7 @@ where + TransactionPaymentConfig, C: ExtensionConfig, R::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, ::OnChargeTransaction: OnChargeTransaction, LaneId: Clone + Copy + Decode + Encode + Debug + TypeInfo, @@ -145,13 +149,12 @@ where /// virtually boosted. The relayer registration (we only boost priority for registered /// relayer transactions) must be checked outside. fn bundled_messages_for_priority_boost( - call_info: Option<&ExtensionCallInfo>, + parsed_call: &ExtensionCallInfo, ) -> Option { // we only boost priority of message delivery transactions - let parsed_call = match call_info { - Some(parsed_call) if parsed_call.is_receive_messages_proof_call() => parsed_call, - _ => return None, - }; + if !parsed_call.is_receive_messages_proof_call() { + return None; + } // compute total number of messages in transaction let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len(); @@ -169,9 +172,7 @@ where /// Given post-dispatch information, analyze the outcome of relayer call and return /// actions that need to be performed on relayer account. fn analyze_call_result( - pre: Option< - Option>, - >, + pre: Option>, info: &DispatchInfo, post_info: &PostDispatchInfo, len: usize, @@ -179,7 +180,7 @@ where ) -> RelayerAccountAction { // We don't refund anything for transactions that we don't support. let (relayer, call_info) = match pre { - Some(Some(pre)) => (pre.relayer, pre.call_info), + Some(pre) => (pre.relayer, pre.call_info), _ => return RelayerAccountAction::None, }; @@ -201,15 +202,14 @@ where // // we are not checking if relayer is registered here - it happens during the slash attempt // - // there are couple of edge cases here: + // there are a couple of edge cases here: // // - when the relayer becomes registered during message dispatch: this is unlikely + relayer // should be ready for slashing after registration; // // - when relayer is registered after `validate` is called and priority is not boosted: // relayer should be ready for slashing after registration. - let may_slash_relayer = - Self::bundled_messages_for_priority_boost(Some(&call_info)).is_some(); + let may_slash_relayer = Self::bundled_messages_for_priority_boost(&call_info).is_some(); let slash_relayer_if_delivery_result = may_slash_relayer .then(|| RelayerAccountAction::Slash(relayer.clone(), reward_account_params)) .unwrap_or(RelayerAccountAction::None); @@ -244,7 +244,7 @@ where let post_info_len = len.saturating_sub(call_data.extra_size as usize); let mut post_info_weight = post_info .actual_weight - .unwrap_or(info.weight) + .unwrap_or(info.total_weight()) .saturating_sub(call_data.extra_weight); // let's also replace the weight of slashing relayer with the weight of rewarding relayer @@ -274,7 +274,8 @@ where } } -impl SignedExtension for BridgeRelayersSignedExtension +impl TransactionExtension + for BridgeRelayersTransactionExtension where Self: 'static + Send + Sync, R: RelayersConfig @@ -282,46 +283,51 @@ where + TransactionPaymentConfig, C: ExtensionConfig, R::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, ::OnChargeTransaction: OnChargeTransaction, LaneId: Clone + Copy + Decode + Encode + Debug + TypeInfo, { const IDENTIFIER: &'static str = C::IdProvider::STR; - type AccountId = R::AccountId; - type Call = R::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); type Pre = Option>; + type Val = Self::Pre; - fn additional_signed(&self) -> Result<(), TransactionValidityError> { - Ok(()) + fn weight(&self, _call: &R::RuntimeCall) -> Weight { + Weight::zero() } fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &R::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { - // this is the only relevant line of code for the `pre_dispatch` - // - // we're not calling `validate` from `pre_dispatch` directly because of performance - // reasons, so if you're adding some code that may fail here, please check if it needs - // to be added to the `pre_dispatch` as well - let parsed_call = C::parse_and_check_for_obsolete_call(call)?; + _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)? { + Some(parsed_call) => parsed_call, + None => return Ok((Default::default(), None, origin)), + }; + // Those calls are only for signed transactions. + let relayer = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + + let data = PreDispatchData { relayer: relayer.clone(), call_info: parsed_call }; - // the following code just plays with transaction priority and never returns an error + // the following code just plays with transaction priority // we only boost priority of presumably correct message delivery transactions - let bundled_messages = match Self::bundled_messages_for_priority_boost(parsed_call.as_ref()) - { + let bundled_messages = match Self::bundled_messages_for_priority_boost(&data.call_info) { Some(bundled_messages) => bundled_messages, - None => return Ok(Default::default()), + None => return Ok((Default::default(), Some(data), origin)), }; // we only boost priority if relayer has staked required balance - if !RelayersPallet::::is_registration_active(who) { - return Ok(Default::default()) + if !RelayersPallet::::is_registration_active(&data.relayer) { + return Ok((Default::default(), Some(data), origin)) } // compute priority boost @@ -334,48 +340,43 @@ where "{}.{:?}: has boosted priority of message delivery transaction \ of relayer {:?}: {} messages -> {} priority", Self::IDENTIFIER, - parsed_call.as_ref().map(|p| p.messages_call_info().lane_id()), - who, + data.call_info.messages_call_info().lane_id(), + data.relayer, bundled_messages, priority_boost, ); - valid_transaction.build() + let validity = valid_transaction.build()?; + Ok((validity, Some(data), origin)) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + val: Self::Val, + _origin: &::RuntimeOrigin, + _call: &R::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, ) -> Result { - // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) - let parsed_call = C::parse_and_check_for_obsolete_call(call)?; - - Ok(parsed_call.map(|call_info| { + Ok(val.inspect(|data| { log::trace!( target: LOG_TARGET, - "{}.{:?}: parsed bridge transaction in pre-dispatch: {:?}", + "{}.{:?}: parsed bridge transaction in prepare: {:?}", Self::IDENTIFIER, - call_info.messages_call_info().lane_id(), - call_info, + data.call_info.messages_call_info().lane_id(), + data.call_info, ); - PreDispatchData { relayer: who.clone(), call_info } })) } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - let lane_id = pre - .as_ref() - .and_then(|p| p.as_ref()) - .map(|p| p.call_info.messages_call_info().lane_id()); + ) -> Result { + let lane_id = pre.as_ref().map(|p| p.call_info.messages_call_info().lane_id()); let call_result = Self::analyze_call_result(pre, info, post_info, len, result); match call_result { @@ -399,7 +400,7 @@ where ), } - Ok(()) + Ok(Weight::zero()) } } @@ -463,8 +464,10 @@ mod tests { use pallet_bridge_parachains::{Call as ParachainsCall, Pallet as ParachainsPallet}; use pallet_utility::Call as UtilityCall; use sp_runtime::{ - traits::{ConstU64, Header as HeaderT}, - transaction_validity::{InvalidTransaction, ValidTransaction}, + traits::{ConstU64, DispatchTransaction, Header as HeaderT}, + transaction_validity::{ + InvalidTransaction, TransactionSource::External, TransactionValidity, ValidTransaction, + }, DispatchError, }; @@ -496,7 +499,7 @@ mod tests { ConstU64<1>, >; type TestGrandpaExtension = - BridgeRelayersSignedExtension; + BridgeRelayersTransactionExtension; type TestExtensionConfig = parachain_adapter::WithParachainExtensionConfig< StrTestExtension, TestRuntime, @@ -507,7 +510,7 @@ mod tests { ConstU64<1>, >; type TestExtension = - BridgeRelayersSignedExtension; + BridgeRelayersTransactionExtension; type TestMessagesExtensionConfig = messages_adapter::WithMessagesExtensionConfig< StrTestMessagesExtension, TestRuntime, @@ -515,8 +518,11 @@ mod tests { (), ConstU64<1>, >; - type TestMessagesExtension = - BridgeRelayersSignedExtension; + type TestMessagesExtension = BridgeRelayersTransactionExtension< + TestRuntime, + TestMessagesExtensionConfig, + TestLaneIdType, + >; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { let test_stake: ThisChainBalance = Stake::get(); @@ -1067,18 +1073,45 @@ mod tests { } fn run_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestExtension = BridgeRelayersSignedExtension(PhantomData); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + External, + 0, + ) + .map(|t| t.0) } fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestGrandpaExtension = BridgeRelayersSignedExtension(PhantomData); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestGrandpaExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + External, + 0, + ) + .map(|t| t.0) } fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestMessagesExtension = BridgeRelayersSignedExtension(PhantomData); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestMessagesExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + External, + 0, + ) + .map(|t| t.0) } fn ignore_priority(tx: TransactionValidity) -> TransactionValidity { @@ -1095,8 +1128,16 @@ mod tests { TransactionValidityError, > { sp_tracing::try_init_simple(); - let extension: TestExtension = BridgeRelayersSignedExtension(PhantomData); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + 0, + ) + .map(|(pre, _)| pre) } fn run_grandpa_pre_dispatch( @@ -1105,8 +1146,16 @@ mod tests { Option>, TransactionValidityError, > { - let extension: TestGrandpaExtension = BridgeRelayersSignedExtension(PhantomData); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestGrandpaExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + 0, + ) + .map(|(pre, _)| pre) } fn run_messages_pre_dispatch( @@ -1115,16 +1164,25 @@ mod tests { Option>, TransactionValidityError, > { - let extension: TestMessagesExtension = BridgeRelayersSignedExtension(PhantomData); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestMessagesExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + 0, + ) + .map(|(pre, _)| pre) } fn dispatch_info() -> DispatchInfo { DispatchInfo { - weight: Weight::from_parts( + call_weight: Weight::from_parts( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, 0, ), + extension_weight: Weight::zero(), class: frame_support::dispatch::DispatchClass::Normal, pays_fee: frame_support::dispatch::Pays::Yes, } @@ -1140,21 +1198,21 @@ mod tests { >, dispatch_result: DispatchResult, ) { - let post_dispatch_result = TestExtension::post_dispatch( - Some(pre_dispatch_data), + let post_dispatch_result = TestExtension::post_dispatch_details( + pre_dispatch_data, &dispatch_info(), &post_dispatch_info(), 1024, &dispatch_result, ); - assert_eq!(post_dispatch_result, Ok(())); + assert_eq!(post_dispatch_result, Ok(Weight::zero())); } fn expected_delivery_reward() -> ThisChainBalance { let mut post_dispatch_info = post_dispatch_info(); let extra_weight = ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(); post_dispatch_info.actual_weight = - Some(dispatch_info().weight.saturating_sub(extra_weight)); + Some(dispatch_info().call_weight.saturating_sub(extra_weight)); pallet_transaction_payment::Pallet::::compute_actual_fee( 1024, &dispatch_info(), @@ -1714,7 +1772,7 @@ mod tests { initialize_environment(200, 200, 200); let mut dispatch_info = dispatch_info(); - dispatch_info.weight = Weight::from_parts( + dispatch_info.call_weight = Weight::from_parts( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, 0, ); @@ -1918,7 +1976,7 @@ mod tests { dispatch_result: DispatchResult, ) -> RelayerAccountAction { TestExtension::analyze_call_result( - Some(Some(pre_dispatch_data)), + Some(pre_dispatch_data), &dispatch_info(), &post_dispatch_info(), 1024, diff --git a/bridges/modules/relayers/src/extension/priority.rs b/bridges/modules/relayers/src/extension/priority.rs index da188eaf5bdd..e09e8627c673 100644 --- a/bridges/modules/relayers/src/extension/priority.rs +++ b/bridges/modules/relayers/src/extension/priority.rs @@ -206,14 +206,17 @@ mod integrity_tests { // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(tx_call_size); - let transaction_weight = Runtime::WeightInfo::submit_finality_proof_weight( + let transaction_weight = >::WeightInfo::submit_finality_proof_weight( Runtime::BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1, Runtime::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY, ); pallet_transaction_payment::ChargeTransactionPayment::::get_priority( &DispatchInfo { - weight: transaction_weight, + call_weight: transaction_weight, + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }, @@ -315,7 +318,8 @@ mod integrity_tests { pallet_transaction_payment::ChargeTransactionPayment::::get_priority( &DispatchInfo { - weight: transaction_weight, + call_weight: transaction_weight, + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }, @@ -385,20 +389,27 @@ mod integrity_tests { // trie nodes to the proof (x0.5 because we expect some nodes to be reused) let estimated_message_size = 512; // let's say all our messages have the same dispatch weight - let estimated_message_dispatch_weight = - Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); + let estimated_message_dispatch_weight = >::WeightInfo::message_dispatch_weight( + estimated_message_size + ); // messages proof argument size is (for every message) messages size + some additional // trie nodes. Some of them are reused by different messages, so let's take 2/3 of // default "overhead" constant - let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() - .saturating_mul(2) - .saturating_div(3) - .saturating_add(estimated_message_size) - .saturating_mul(messages as _); + let messages_proof_size = >::WeightInfo::expected_extra_storage_proof_size() + .saturating_mul(2) + .saturating_div(3) + .saturating_add(estimated_message_size) + .saturating_mul(messages as _); // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(messages_proof_size); - let transaction_weight = Runtime::WeightInfo::receive_messages_proof_weight( + let transaction_weight = >::WeightInfo::receive_messages_proof_weight( &PreComputedSize(transaction_size as _), messages as _, estimated_message_dispatch_weight.saturating_mul(messages), @@ -406,7 +417,8 @@ mod integrity_tests { pallet_transaction_payment::ChargeTransactionPayment::::get_priority( &DispatchInfo { - weight: transaction_weight, + call_weight: transaction_weight, + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }, diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 7ba524e95b1d..fe8f5a2efdfb 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -99,7 +99,7 @@ pub mod pallet { type DestinationVersion: GetVersion; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. - type ToBridgeHubSender: SendXcm + InspectMessageQueues; + type ToBridgeHubSender: SendXcm; /// Local XCM channel manager. type LocalXcmChannelManager: XcmChannelStatusProvider; @@ -408,12 +408,12 @@ impl, I: 'static> SendXcm for Pallet { } impl, I: 'static> InspectMessageQueues for Pallet { - fn clear_messages() { - ViaBridgeHubExporter::::clear_messages() - } + fn clear_messages() {} + /// This router needs to implement `InspectMessageQueues` but doesn't have to + /// return any messages, since it just reuses the `XcmpQueue` router. fn get_messages() -> Vec<(VersionedLocation, Vec>)> { - ViaBridgeHubExporter::::get_messages() + Vec::new() } } @@ -646,34 +646,13 @@ mod tests { } #[test] - fn get_messages_works() { + fn get_messages_does_not_return_anything() { run_test(|| { assert_ok!(send_xcm::( (Parent, Parent, GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)).into(), vec![ClearOrigin].into() )); - assert_eq!( - XcmBridgeHubRouter::get_messages(), - vec![( - VersionedLocation::V4((Parent, Parachain(1002)).into()), - vec![VersionedXcm::V4( - Xcm::builder() - .withdraw_asset((Parent, 1_002_000)) - .buy_execution((Parent, 1_002_000), Unlimited) - .set_appendix( - Xcm::builder_unsafe() - .deposit_asset(AllCounted(1), (Parent, Parachain(1000))) - .build() - ) - .export_message( - Kusama, - Parachain(1000), - Xcm::builder_unsafe().clear_origin().build() - ) - .build() - )], - ),], - ); + assert_eq!(XcmBridgeHubRouter::get_messages(), vec![]); }); } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index bb265e1925a2..095572883920 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -141,8 +141,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/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 6511b9fc5b04..9f06b99ef6d5 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -38,7 +38,7 @@ 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, @@ -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; diff --git a/bridges/primitives/header-chain/src/justification/verification/equivocation.rs b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs index fbad30128199..bfcd22f8ca6a 100644 --- a/bridges/primitives/header-chain/src/justification/verification/equivocation.rs +++ b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs @@ -34,6 +34,8 @@ use sp_runtime::traits::Header as HeaderT; use sp_std::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, prelude::*, + vec, + vec::Vec, }; enum AuthorityVotes { diff --git a/bridges/primitives/header-chain/src/justification/verification/mod.rs b/bridges/primitives/header-chain/src/justification/verification/mod.rs index 9df3511e1035..9941537eb095 100644 --- a/bridges/primitives/header-chain/src/justification/verification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/verification/mod.rs @@ -35,6 +35,8 @@ use sp_std::{ btree_set::BTreeSet, }, prelude::*, + vec, + vec::Vec, }; type SignedPrecommit
= finality_grandpa::SignedPrecommit< diff --git a/bridges/primitives/header-chain/src/justification/verification/optimizer.rs b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs index 3f1e6ab670ca..5098b594db68 100644 --- a/bridges/primitives/header-chain/src/justification/verification/optimizer.rs +++ b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs @@ -26,7 +26,7 @@ use crate::justification::verification::{ }; use sp_consensus_grandpa::AuthorityId; use sp_runtime::traits::Header as HeaderT; -use sp_std::{collections::btree_set::BTreeSet, prelude::*}; +use sp_std::{collections::btree_set::BTreeSet, prelude::*, vec, vec::Vec}; // Verification callbacks for justification optimization. struct JustificationOptimizer { 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/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index 366ee7aa948e..295fb281e9bb 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -12,7 +12,6 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -parity-util-mem = { optional = true, workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = [ "derive", @@ -42,7 +41,6 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", - "parity-util-mem", "scale-info/std", "serde", "sp-core/std", diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index e83be59b2389..a8abdb59bea3 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -24,8 +24,8 @@ use bp_runtime::{ self, extensions::{ ChargeTransactionPayment, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, - CheckSpecVersion, CheckTxVersion, CheckWeight, GenericSignedExtension, - SignedExtensionSchema, + CheckSpecVersion, CheckTxVersion, CheckWeight, GenericTransactionExtension, + TransactionExtensionSchema, }, EncodedOrDecodedCall, StorageMapKeyProvider, TransactionEra, }; @@ -229,8 +229,12 @@ pub type SignedBlock = generic::SignedBlock; pub type Balance = u128; /// Unchecked Extrinsic type. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic, Signature, SignedExt>; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< + AccountAddress, + EncodedOrDecodedCall, + Signature, + TransactionExt, +>; /// Account address, used by the Polkadot-like chain. pub type Address = MultiAddress; @@ -275,7 +279,7 @@ impl AccountInfoStorageMapKeyProvider { } /// Extra signed extension data that is used by most chains. -pub type CommonSignedExtra = ( +pub type CommonTransactionExtra = ( CheckNonZeroSender, CheckSpecVersion, CheckTxVersion, @@ -286,12 +290,12 @@ pub type CommonSignedExtra = ( ChargeTransactionPayment, ); -/// Extra signed extension data that starts with `CommonSignedExtra`. -pub type SuffixedCommonSignedExtension = - GenericSignedExtension<(CommonSignedExtra, Suffix)>; +/// Extra transaction extension data that starts with `CommonTransactionExtra`. +pub type SuffixedCommonTransactionExtension = + GenericTransactionExtension<(CommonTransactionExtra, Suffix)>; -/// Helper trait to define some extra methods on `SuffixedCommonSignedExtension`. -pub trait SuffixedCommonSignedExtensionExt { +/// Helper trait to define some extra methods on `SuffixedCommonTransactionExtension`. +pub trait SuffixedCommonTransactionExtensionExt { /// Create signed extension from its components. fn from_params( spec_version: u32, @@ -300,7 +304,7 @@ pub trait SuffixedCommonSignedExtensionExt { genesis_hash: Hash, nonce: Nonce, tip: Balance, - extra: (Suffix::Payload, Suffix::AdditionalSigned), + extra: (Suffix::Payload, Suffix::Implicit), ) -> Self; /// Return transaction nonce. @@ -310,9 +314,10 @@ pub trait SuffixedCommonSignedExtensionExt { fn tip(&self) -> Balance; } -impl SuffixedCommonSignedExtensionExt for SuffixedCommonSignedExtension +impl SuffixedCommonTransactionExtensionExt + for SuffixedCommonTransactionExtension where - Suffix: SignedExtensionSchema, + Suffix: TransactionExtensionSchema, { fn from_params( spec_version: u32, @@ -321,9 +326,9 @@ where genesis_hash: Hash, nonce: Nonce, tip: Balance, - extra: (Suffix::Payload, Suffix::AdditionalSigned), + extra: (Suffix::Payload, Suffix::Implicit), ) -> Self { - GenericSignedExtension::new( + GenericTransactionExtension::new( ( ( (), // non-zero sender @@ -365,7 +370,7 @@ where } /// Signed extension that is used by most chains. -pub type CommonSignedExtension = SuffixedCommonSignedExtension<()>; +pub type CommonTransactionExtension = SuffixedCommonTransactionExtension<()>; #[cfg(test)] mod tests { diff --git a/bridges/primitives/polkadot-core/src/parachains.rs b/bridges/primitives/polkadot-core/src/parachains.rs index d54ee108386e..a8b1cf6eebf4 100644 --- a/bridges/primitives/polkadot-core/src/parachains.rs +++ b/bridges/primitives/polkadot-core/src/parachains.rs @@ -32,9 +32,6 @@ use sp_std::vec::Vec; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] -use parity_util_mem::MallocSizeOf; - /// Parachain id. /// /// This is an equivalent of the `polkadot_parachain_primitives::Id`, which is a compact-encoded @@ -71,7 +68,7 @@ impl From for ParaId { #[derive( PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default, )] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, MallocSizeOf))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))] pub struct ParaHead(pub Vec); impl ParaHead { diff --git a/bridges/primitives/relayers/src/extension.rs b/bridges/primitives/relayers/src/extension.rs index a9fa4df27ead..8fd0f151e2a5 100644 --- a/bridges/primitives/relayers/src/extension.rs +++ b/bridges/primitives/relayers/src/extension.rs @@ -138,7 +138,7 @@ pub trait ExtensionConfig { /// Lane identifier type. type LaneId: Clone + Copy + Decode + Encode + Debug; - /// Given runtime call, check if it is supported by the signed extension. Additionally, + /// Given runtime call, check if it is supported by the transaction extension. Additionally, /// check if call (or any of batched calls) are obsolete. fn parse_and_check_for_obsolete_call( call: &::RuntimeCall, diff --git a/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs index d896bc92efff..25553f9c7b2e 100644 --- a/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -20,135 +20,131 @@ use codec::{Compact, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::{Dispatchable, TransactionExtension}, transaction_validity::TransactionValidityError, }; use sp_std::{fmt::Debug, marker::PhantomData}; -/// Trait that describes some properties of a `SignedExtension` that are needed in order to send a -/// transaction to the chain. -pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo { +/// Trait that describes some properties of a `TransactionExtension` that are needed in order to +/// send a transaction to the chain. +pub trait TransactionExtensionSchema: + Encode + Decode + Debug + Eq + Clone + StaticTypeInfo +{ /// A type of the data encoded as part of the transaction. type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; /// Parameters which are part of the payload used to produce transaction signature, /// but don't end up in the transaction itself (i.e. inherent part of the runtime). - type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo; + type Implicit: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; } -impl SignedExtensionSchema for () { +impl TransactionExtensionSchema for () { type Payload = (); - type AdditionalSigned = (); + type Implicit = (); } -/// An implementation of `SignedExtensionSchema` using generic params. +/// An implementation of `TransactionExtensionSchema` using generic params. #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)] -pub struct GenericSignedExtensionSchema(PhantomData<(P, S)>); +pub struct GenericTransactionExtensionSchema(PhantomData<(P, S)>); -impl SignedExtensionSchema for GenericSignedExtensionSchema +impl TransactionExtensionSchema for GenericTransactionExtensionSchema where P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, - S: Encode + Debug + Eq + Clone + StaticTypeInfo, + S: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, { type Payload = P; - type AdditionalSigned = S; + type Implicit = S; } -/// The `SignedExtensionSchema` for `frame_system::CheckNonZeroSender`. -pub type CheckNonZeroSender = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `frame_system::CheckNonZeroSender`. +pub type CheckNonZeroSender = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `frame_system::CheckSpecVersion`. -pub type CheckSpecVersion = GenericSignedExtensionSchema<(), u32>; +/// The `TransactionExtensionSchema` for `frame_system::CheckSpecVersion`. +pub type CheckSpecVersion = GenericTransactionExtensionSchema<(), u32>; -/// The `SignedExtensionSchema` for `frame_system::CheckTxVersion`. -pub type CheckTxVersion = GenericSignedExtensionSchema<(), u32>; +/// The `TransactionExtensionSchema` for `frame_system::CheckTxVersion`. +pub type CheckTxVersion = GenericTransactionExtensionSchema<(), u32>; -/// The `SignedExtensionSchema` for `frame_system::CheckGenesis`. -pub type CheckGenesis = GenericSignedExtensionSchema<(), Hash>; +/// The `TransactionExtensionSchema` for `frame_system::CheckGenesis`. +pub type CheckGenesis = GenericTransactionExtensionSchema<(), Hash>; -/// The `SignedExtensionSchema` for `frame_system::CheckEra`. -pub type CheckEra = GenericSignedExtensionSchema; +/// The `TransactionExtensionSchema` for `frame_system::CheckEra`. +pub type CheckEra = GenericTransactionExtensionSchema; -/// The `SignedExtensionSchema` for `frame_system::CheckNonce`. -pub type CheckNonce = GenericSignedExtensionSchema, ()>; +/// The `TransactionExtensionSchema` for `frame_system::CheckNonce`. +pub type CheckNonce = GenericTransactionExtensionSchema, ()>; -/// The `SignedExtensionSchema` for `frame_system::CheckWeight`. -pub type CheckWeight = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `frame_system::CheckWeight`. +pub type CheckWeight = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. -pub type ChargeTransactionPayment = GenericSignedExtensionSchema, ()>; +/// The `TransactionExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. +pub type ChargeTransactionPayment = + GenericTransactionExtensionSchema, ()>; -/// The `SignedExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. -pub type PrevalidateAttests = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. +pub type PrevalidateAttests = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. -pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. +pub type BridgeRejectObsoleteHeadersAndMessages = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `RefundBridgedParachainMessages`. +/// The `TransactionExtensionSchema` for `RefundBridgedParachainMessages`. /// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as /// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (), /// ())` is the same. So runtime can contains any kind of tuple: /// `(BridgeRefundBridgeHubRococoMessages)` /// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)` /// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)` -pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>; +pub type RefundBridgedParachainMessagesSchema = GenericTransactionExtensionSchema<(), ()>; #[impl_for_tuples(1, 12)] -impl SignedExtensionSchema for Tuple { +impl TransactionExtensionSchema for Tuple { for_tuples!( type Payload = ( #( Tuple::Payload ),* ); ); - for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); + for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); } /// A simplified version of signed extensions meant for producing signed transactions /// and signed payloads in the client code. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct GenericSignedExtension { +pub struct GenericTransactionExtension { /// A payload that is included in the transaction. pub payload: S::Payload, #[codec(skip)] // It may be set to `None` if extensions are decoded. We are never reconstructing transactions - // (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to - // read fields of the `payload`. And when resigning transaction, we're reconstructing - // `SignedExtensions` from scratch. - additional_signed: Option, + // (and it makes no sense to do that) => decoded version of `TransactionExtensions` is only + // used to read fields of the `payload`. And when resigning transaction, we're reconstructing + // `TransactionExtensions` from scratch. + implicit: Option, } -impl GenericSignedExtension { - /// Create new `GenericSignedExtension` object. - pub fn new(payload: S::Payload, additional_signed: Option) -> Self { - Self { payload, additional_signed } +impl GenericTransactionExtension { + /// Create new `GenericTransactionExtension` object. + pub fn new(payload: S::Payload, implicit: Option) -> Self { + Self { payload, implicit } } } -impl SignedExtension for GenericSignedExtension +impl TransactionExtension for GenericTransactionExtension where - S: SignedExtensionSchema, + C: Dispatchable, + S: TransactionExtensionSchema, S::Payload: Send + Sync, - S::AdditionalSigned: Send + Sync, + S::Implicit: Send + Sync, { const IDENTIFIER: &'static str = "Not needed."; - type AccountId = (); - type Call = (); - type AdditionalSigned = S::AdditionalSigned; - type Pre = (); + type Implicit = S::Implicit; - fn additional_signed(&self) -> Result { + fn implicit(&self) -> Result { // we shall not ever see this error in relay, because we are never signing decoded // transactions. Instead we're constructing and signing new transactions. So the error code // is kinda random here - self.additional_signed.clone().ok_or( - frame_support::unsigned::TransactionValidityError::Unknown( + self.implicit + .clone() + .ok_or(frame_support::unsigned::TransactionValidityError::Unknown( frame_support::unsigned::UnknownTransaction::Custom(0xFF), - ), - ) + )) } + type Pre = (); + type Val = (); - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } + impl_tx_ext_default!(C; weight validate prepare); } diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 061e7a275063..63beb1bc3041 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -359,10 +359,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/lib-substrate-relay/src/cli/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/mod.rs index be64866fc14b..d7aa38f1f2ba 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/mod.rs @@ -20,7 +20,6 @@ use rbtag::BuildInfo; use sp_runtime::traits::TryConvert; use std::str::FromStr; use structopt::StructOpt; -use strum::{EnumString, VariantNames}; pub mod bridge; pub mod chain_schema; @@ -139,17 +138,6 @@ where } } -#[doc = "Runtime version params."] -#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)] -pub enum RuntimeVersionType { - /// Auto query version from chain - Auto, - /// Custom `spec_version` and `transaction_version` - Custom, - /// Read version from bundle dependencies directly. - Bundle, -} - #[cfg(test)] mod tests { use super::*; diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs index ea92a0c9acce..308b041c46f7 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs @@ -96,6 +96,7 @@ pub trait HeadersRelayer: RelayToRelayHeadersCliBridge { signer: target_sign, mortality: target_transactions_mortality, }; + Self::Finality::start_relay_guards(&target_client, target_client.can_start_version_guard()) .await?; diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index 3878b081d6c3..71d3adc078e2 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -121,6 +121,8 @@ where anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) })?; + Self::start_relay_guards(&target_client, target_client.can_start_version_guard()).await?; + crate::messages::run::(MessagesRelayParams { source_client, source_transaction_params: TransactionParams { @@ -216,4 +218,18 @@ where ) .await } + + /// Add relay guards if required. + async fn start_relay_guards( + target_client: &impl Client, + enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + Ok(()) + } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs index 77cd395ff722..83285b69f701 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs @@ -32,6 +32,7 @@ use crate::{ chain_schema::*, DefaultClient, PrometheusParams, }, + finality::SubstrateFinalitySyncPipeline, parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter}, TransactionParams, }; @@ -104,6 +105,12 @@ where data.prometheus_params.into_metrics_params()?; GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; + Self::RelayFinality::start_relay_guards( + target_client.target_client(), + target_client.target_client().can_start_version_guard(), + ) + .await?; + parachains_relay::parachains_loop::run( source_client, target_client, diff --git a/bridges/relays/lib-substrate-relay/src/messages/mod.rs b/bridges/relays/lib-substrate-relay/src/messages/mod.rs index f7031648bc35..b4ee57ed7742 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/mod.rs @@ -428,7 +428,7 @@ where "Prepared {} -> {} messages delivery call. Weight: {}/{}, size: {}/{}", P::SourceChain::NAME, P::TargetChain::NAME, - call.get_dispatch_info().weight, + call.get_dispatch_info().call_weight, P::TargetChain::max_extrinsic_weight(), call.encode().len(), P::TargetChain::max_extrinsic_size(), @@ -521,7 +521,7 @@ where "Prepared {} -> {} delivery confirmation transaction. Weight: {}/{}, size: {}/{}", P::TargetChain::NAME, P::SourceChain::NAME, - call.get_dispatch_info().weight, + call.get_dispatch_info().call_weight, P::SourceChain::max_extrinsic_weight(), call.encode().len(), P::SourceChain::max_extrinsic_size(), diff --git a/bridges/relays/parachains/src/parachains_loop.rs b/bridges/relays/parachains/src/parachains_loop.rs index 59ca458e6667..dfe6b230ceda 100644 --- a/bridges/relays/parachains/src/parachains_loop.rs +++ b/bridges/relays/parachains/src/parachains_loop.rs @@ -177,6 +177,14 @@ pub async fn run( where P::SourceRelayChain: Chain, { + log::info!( + target: "bridge", + "Starting {} -> {} finality proof relay: relaying (only_free_headers: {:?}) headers", + P::SourceParachain::NAME, + P::TargetChain::NAME, + only_free_headers, + ); + let exit_signal = exit_signal.shared(); relay_utils::relay_loop(source_client, target_client) .with_metrics(metrics_params) diff --git a/bridges/snowbridge/docs/v2.md b/bridges/snowbridge/docs/v2.md new file mode 100644 index 000000000000..8ec440c47cec --- /dev/null +++ b/bridges/snowbridge/docs/v2.md @@ -0,0 +1,356 @@ +# Snowbridge V2 + +This design lowers fees, improves UX, improves relayer decentralization and allows "transacting" over the bridge, making +it a general-purpose bridge rather than just a token bridge. + +We're grateful to Adrian Catangiu, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and +collaboration on this design. + +## Summary + +- Unordered messaging +- All messages routed through AH +- Off-chain fee estimation +- P→E Fee Asset: WETH +- E→P Fee Asset: ETH +- Relayer rewards for both directions paid out on AH in WETH + +## Polkadot→Ethereum + +Given source parachain $S$, with native token $S^{'}$ and the initial xcm $x_0$ to be executed on $S$. + +### Step 1: User agent constructs initial XCM + +The user agent constructs an initial XCM message $x_0$ that will be executed on S. + +The fee amounts in this message should be high enough to enable dry-running, after which they will be lowered. + +### Step 2: User agent estimates fees + +- Given source parachain $S$, with native token $S^{'}$ and the initial xcm $x_0$ to be executed on $S$. +- The native currency $P^{'}$ (DOT) of the Polkadot relay chain, and $E^{'}$ (ETH) of Ethereum. +- Suppose that the user agent chooses relayer reward $r$ in $E^{'}$. +- Suppose that the exchange rates are $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to + $\beta$ to cover volatility in these rates. + +Apply the following sequence operations: + +1. Dry-run $x_0$ on $S$ to receive xcm $x_1$ and cost $a$ in $S^{'}$ +2. Dry-run $x_1$ on AH to receive xcm $x_2$ and cost $b$ in $P^{'}$ (DOT) +3. Dry-run $x_2$ on BH to receive command $m$ and cost $c$ in $P^{'}$ (DOT) +4. Dry-run $m$ on Ethereum to receive cost $d$ in $E^{'}$ (ETH) + +The final cost to the user in $S^{'}$ is given by + +$$ +\beta \left(a + \frac{b + c}{K_{P^{'}/S^{'}}} + \frac{d + r}{K_{E^{'}/S^{'}}}\right) +$$ + +The user agent should perform a final update to xcm $x_0$, substituting the calculated fee amounts. + +### Step 3: User agent initiates bridging operation + +The user agent calls `pallet_xcm::execute` with the initial xcm $x_0$ + +```text +WithdrawAsset (KLT, 100) +PayFees (KLT, 20) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(KLT, 20) dest=AH + ExchangeAsset give=(KLT, 20) want=(WETH, 1) + InitiateAssetsTransfer asset=(KLT, 40) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 40) beneficiary=Bob +``` + +### Step 4: AH executes message x1 + +The message $x_1$ is application-specific: + +```text +ReserveAssetDeposited (KLT, 80) +PayFees (KLT, 20) +SetAssetClaimer Kilt/Alice +AliasOrigin Kilt/Alice +ExchangeAsset give=(KLT, 20) want=(WETH, 1) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 60) beneficiary=Bob +``` + +or + +```text +*ReserveAssetDeposited (KLT, 80) +*PayFees (KLT, 20) +*SetAssetClaimer Kilt/Alice +*AliasOrigin Kilt/Alice +ExchangeAsset give=(KLT, 20) want=(WETH, 1) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 60) beneficiary=Bob + Transact Bob.hello() +``` + +Note that the `SetAssetClaimer` instruction is placed before `AliasOrigin` in case AH fails to interpret the latter +instruction. + +In all cases, $x_1$ should contain the necessary instructions to: + +1. Pay fees for local execution using `PaysFees` +2. Obtain WETH for remote delivery fees. + +The XCM bridge-router on AH will charge a small fee to prevent spamming BH with bridge messages. This is necessary since +the `ExportMessage` instruction in message $x_2$ will have no execution fee on BH. For a similar reason, we should also +impose a minimum relayer reward of at least the existential deposit 0.1 DOT, which acts as a deposit to stop spamming +messages with 0 rewards. + +### Step 5: BH executes message x2 + +Message $x_2$ is parsed by the `SnowbridgeMessageExporter` in block $n$ with the following effects: + +- A bridge command $m$ is committed to binary merkle tree $M_n$. + - The transferred asset is parsed from `ReserveAssetDeposited` , `WithdrawAsset` or `TeleportedAssetReceived` + instructions for the local, destination and teleport asset transfer types respectively. + - The original origin is preserved through the `AliasOrigin` instruction. This will allow us to resolve agents for the + case of `Transact`. + - The message exporter must be able to support multiple assets and reserve types in the same message and potentially + multiple `Transacts`. + - The Message Exporter must be able to support multiple Deposited Assets. + - The Message Exporter must be able to parse `SetAssetClaimer` and allow the provided location to claim the assets on + BH in case of errors. +- Given relayer reward $r$ in WETH, set storage $P(\mathrm{hash}(m)) = r$. This is parsed from the `WithdrawAsset` and + `PayFees` instruction within `ExportMessage`. + +Note that WETH on AH & BH is a wrapped derivative of the +[WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) ERC20 contract on Ethereum, which is +itself a wrapper over ETH, the native currency of Ethereum. For the purposes of this document you can consider them all +to be of equivalent value. + +```text +!WithdrawAsset(DOT, 10) +!PayFees (DOT, 10) +!ExportMessage dest=Ethereum + *ReserveAssetDeposited (KLT, 60) + *WithdrawAsset (WETH, 1) + *PayFees (WETH, 1) + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob +``` + +or + +```text +!WithdrawAsset(DOT, 10) +!PayFees (DOT, 10) +!ExportMessage dest=Ethereum + *ReserveAssetDeposited (KLT, 80) + *PayFees (KLT, 20) + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob + Transact Bob.hello() +``` + +### Step 6: Relayer relays message to Gateway + +1. A relayer _Charlie_ inspects storage $P$ to look for new messages to relay. Suppose it finds $\mathrm{hash}(m)$ + giving reward $r$. +2. The relayer queries $m$ from $M$ and constructs the necessary proofs. +3. The relayer dry-runs m on Ethereum to decide whether the message is profitable to deliver. +4. The relayer finally delivers the message together with a relayer-controlled address $u$ on AH where the relayer can + claim their reward after proof of delivery. + +### Step 7: Relayer delivers proof of delivery to BH + +The proof of delivery is essentially a merkle proof for the `InboundMessageAccepted` event log. + +When BH processes the proof of delivery: + +1. The command $m$ is removed from storage items $M$ and $P$. +2. The relayer reward is tracked in storage $R$, where $R(u)$ is the accumulated rewards that can be claimed by account + $u$. + +## Ethereum→Polkadot + +### Step 1: Submit send on Gateway + +The interface that the Gateway will use to initiate transfers will be similar to the interface from +`transfer_assets_using_type_and_then` extrinsic that we currently use to initiate transfers from the Polkadot to +Ethereum direction. + +1. It must allow multiple assets to be transferred and specify the transfer type: Local, Destination or Teleport asset + transfer types. It is the job of the User Agent/UX layer to fill in this information correctly. +2. It must allow specifying a destination which is `Address32`, `Address20` or a custom scale-encoded XCM payload that + is executed on the destination. This is how we will support `Transact` , the User Agent/UX layer can build a + scale-encoded payload with an encoded transact call. +3. The same interface is used for both PNA (Polkadot Assets) and ERC20 tokens. Internally we will still look up whether + the token is registered as a PNA or ERC20 for the purpose of minting/locking burning/unlocking logic. The asset + transfer type chosen by the UX layer will inform the XCM that is built from the message on BH. + +```solidity +enum Kind { + Index, + Address32, + Address20, + XCMPayload, +} + +struct Beneficiary { + Kind kind; + bytes data; +} + +enum AssetTransferType { + ReserveDeposit, ReserveWithdraw, Teleport +} + +struct Token { + AssetTransferType type; + address token; + uint128 amount; +} + +function send( + ParaID destinationChain, + Beneficiary calldata beneficiary, + Token[] tokens, + uint128 reward +) external payable; +``` + +Message enqueued $m_0$: + +```solidity +send( + 3022, // KILT Para Id + Address32(0x0000....), + [(ReserveWithdraw, KLT, 100)], + 10, // WETH +) +``` + +```solidity +send { value: 3 }( // Send 3 Eth for fees and reward + 3022, // KILT Para Id + XCMPayload( + DepositAsset (KLT, 100) dest=Bob + Transact Bob.hello() + ), + [(ReserveWithdraw, KLT, 100)], + 1, // 1 ETH of 3 needs to be for the reward, the rest is for fees +) +``` + +The User Agent/UX layer will need to estimate the fee required to be passed into the `send` method. This may be an issue +as we cannot Dry-Run something on Polkadot that has not even been submitted on Ethereum yet. We may need to make RPC API +to DryRun and get back the xcm that would be submitted to asset hub. + +### Step 2: Relayer relays message to Bridge Hub + +On-chain exchange rate is eliminated. Users pay remote delivery costs in ETH, and this amount is sent with the message +as WETH. The delivery fee can be claimed by the relayer on BH. + +The user agent applies a similar dry-running process as with +[Step 2: User agent estimates fees](https://www.notion.so/Step-2-User-agent-estimates-fees-113296aaabef8159bcd0e6dd2e64c3d0?pvs=21). + +The message is converted from $m_0$ to $x_0$ during message submission on BH. Dry-running submission will return $x_0$ +to the relayer so that it can verify it is profitable. + +### Step 3: AH receives $x_0$ from BH + +Submitting the message $m_0$ will cause the following XCM, $x_0$, to be built on BH and dispatched to AH. + +```text +WithdrawAsset (KLT, 100) +ReserveAssetDeposited(WETH, 2) +PayFees (WETH, 1) +SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination +AliasOrigin Ethereum/Alice // derived from msg.sender +InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT + DepositAsset (KLT, 100) beneficiary=Bob +``` + +```text +WithdrawAsset (KLT, 100) +ReserveAssetDeposited(WETH, 2) +PayFees (WETH, 1) +SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination +AliasOrigin Ethereum/Alice // derived from msg.sender +InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT + DepositAsset (KLT, 100) beneficiary=Bob + Transact Bob.hello() +``` + +### Step 4: KILT Receives XCM from AH + +The following XCM $x_1$ is received from AH on KILT. + +```text +*WithdrawAsset (KLT, 100) +*ReserveAssetDeposited (WETH, 1) +*PayFees (WETH, 1) +*SetAssetClaimer Ethereum/Alice +*AliasOrigin Ethereum/Alice // origin preserved from AH +SetAssetClaimer Bob +DepositAsset (KLT, 100) beneficiary=Bob +``` + +```text +*WithdrawAsset (KLT, 100) +*ReserveAssetDeposited (WETH, 1) +*PayFees (WETH, 1) +*SetAssetClaimer Ethereum/Alice +*AliasOrigin Ethereum/Alice // origin preserved from AH +SetAssetClaimer Bob +DepositAsset (KLT, 100) beneficiary=Bob +Transact Bob.hello() // executes with the origin from AH +``` + +## Relayer Rewards + +The tracking and disbursement of relayer rewards for both directions has been unified. Rewards are accumulated on BH in +WETH and must be manually claimed. As part of the claims flow, an XCM instruction is sent to AH to mint the WETH into +the deposit account chosen by the relayer. + +To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will +be minted. + +$$ +\mathrm{claim}(o,w) +$$ + +For tax accounting purposes it might be desirable that $o \neq w$. + +## Top-Up + +Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub and Ethereum +respectively. + +## Origin Preservation + +Origins for transact will be preserved by use of the `AliasOrigin` instruction. This instruction will have the following +rules that parachain runtimes will need to allow: + +1. `AliasOrigin` can behave like `DescendOrigin`. This is safe because it respects the hierarchy of multi-locations and + does not allow jumping up. Meaning no escalation of privileges. + 1. Example location `Ethereum` can alias into `Ethereum/Alice` because we are descending in origin and this + essentially is how the `DescendOrigin` instruction works. +2. `AliasOrigin` must allow AH to alias into bridged locations such as + `{ parents: 2, interior: GlobalConsensus(Ethereum) }` and all of its internal locations so that AH can act as a proxy + for the bridge on parachains. + +`AliasOrigin` will be inserted by every `InitiateAssetTransfer` instruction on the source parachain, populated with the +contents of the origin register, essentially forwarding the origin of the source to the destination. + +RFCS: + +[https://github.com/polkadot-fellows/RFCs/pull/122](https://github.com/polkadot-fellows/RFCs/pull/122) + +[https://github.com/polkadot-fellows/RFCs/blob/main/text/0100-xcm-multi-type-asset-transfer.md](https://github.com/polkadot-fellows/RFCs/blob/main/text/0100-xcm-multi-type-asset-transfer.md) + +## Parachain Requirements + +1. Pallet-xcm.execute enabled. +2. XCM payment and dry run apis implemented. +3. Must accept WETH needed for fees. Though in future user agents can inject `ExchangeAsset` instructions to obtain + WETH. +4. Trust AH as a reserve for bridged assets. +5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses. diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index 666ac3fbc8a2..262d9a7f380d 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -49,13 +49,7 @@ serde = { workspace = true, default-features = true } [features] default = ["std"] -fuzzing = [ - "hex-literal", - "pallet-timestamp", - "serde", - "serde_json", - "sp-io", -] +fuzzing = ["hex-literal", "pallet-timestamp", "serde", "serde_json", "sp-io"] std = [ "codec/std", "frame-support/std", diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml index bd4176875733..87f0cf9a5513 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml @@ -29,6 +29,4 @@ std = [ "sp-core/std", "sp-std/std", ] -runtime-benchmarks = [ - "snowbridge-core/runtime-benchmarks", -] +runtime-benchmarks = ["snowbridge-core/runtime-benchmarks"] diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml index b66b57c3620a..6162a17728b6 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml @@ -29,6 +29,4 @@ std = [ "sp-core/std", "sp-std/std", ] -runtime-benchmarks = [ - "snowbridge-core/runtime-benchmarks", -] +runtime-benchmarks = ["snowbridge-core/runtime-benchmarks"] diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 3e67d5ab738b..675d4b691593 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")] diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 41c38460aabf..76d0b98e9eb4 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -40,8 +40,8 @@ fn test_submit_happy_path() { .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, + 11, 25, 133, 51, 23, 68, 111, 211, 132, 94, 254, 17, 194, 252, 198, 233, 10, 193, + 156, 93, 72, 140, 65, 69, 79, 155, 154, 28, 141, 166, 171, 255, ], fee_burned: 110000000000, } diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 9d4cffc98d78..16241428df80 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -30,9 +30,4 @@ sp-tracing = { workspace = true, default-features = true } [features] default = ["std"] -std = [ - "codec/std", - "scale-info/std", - "sp-core/std", - "sp-runtime/std", -] +std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/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/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/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index fbfc52d01c83..e03560f66e24 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,6 @@ 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), call: ( create_call_index, asset_id, @@ -416,6 +415,8 @@ where // Final destination is a 32-byte account on AssetHub Destination::AccountId32 { id } => Ok(Location::new(0, [AccountId32 { network: None, id }])), + // Forwarding to a destination parachain is not allowed for PNA and is validated on the + // Ethereum side. https://github.com/Snowfork/snowbridge/blob/e87ddb2215b513455c844463a25323bb9c01ff36/contracts/src/Assets.sol#L216-L224 _ => Err(ConvertMessageError::InvalidDestination), }?; @@ -452,22 +453,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/mod.rs b/bridges/snowbridge/primitives/router/src/outbound/mod.rs index efc1ef56f304..3b5dbdb77c89 100644 --- a/bridges/snowbridge/primitives/router/src/outbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/outbound/mod.rs @@ -207,9 +207,9 @@ where fn convert(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> { let result = match self.peek() { - Ok(ReserveAssetDeposited { .. }) => self.send_native_tokens_message(), + Ok(ReserveAssetDeposited { .. }) => self.make_mint_foreign_token_command(), // Get withdraw/deposit and make native tokens create message. - Ok(WithdrawAsset { .. }) => self.send_tokens_message(), + Ok(WithdrawAsset { .. }) => self.make_unlock_native_token_command(), Err(e) => Err(e), _ => return Err(XcmConverterError::UnexpectedInstruction), }?; @@ -222,7 +222,9 @@ where Ok(result) } - fn send_tokens_message(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> { + fn make_unlock_native_token_command( + &mut self, + ) -> Result<(Command, [u8; 32]), XcmConverterError> { use XcmConverterError::*; // Get the reserve assets from WithdrawAsset. @@ -271,7 +273,12 @@ where ensure!(reserve_assets.len() == 1, TooManyAssets); let reserve_asset = reserve_assets.get(0).ok_or(AssetResolutionFailed)?; - // If there was a fee specified verify it. + // Fees are collected on AH, up front and directly from the user, to cover the + // complete cost of the transfer. Any additional fees provided in the XCM program are + // refunded to the beneficiary. We only validate the fee here if its provided to make sure + // the XCM program is well formed. Another way to think about this from an XCM perspective + // would be that the user offered to pay X amount in fees, but we charge 0 of that X amount + // (no fee) and refund X to the user. if let Some(fee_asset) = fee_asset { // The fee asset must be the same as the reserve asset. if fee_asset.id != reserve_asset.id || fee_asset.fun > reserve_asset.fun { @@ -328,7 +335,9 @@ where /// # BuyExecution /// # DepositAsset /// # SetTopic - fn send_native_tokens_message(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> { + fn make_mint_foreign_token_command( + &mut self, + ) -> Result<(Command, [u8; 32]), XcmConverterError> { use XcmConverterError::*; // Get the reserve assets. @@ -377,7 +386,12 @@ where ensure!(reserve_assets.len() == 1, TooManyAssets); let reserve_asset = reserve_assets.get(0).ok_or(AssetResolutionFailed)?; - // If there was a fee specified verify it. + // Fees are collected on AH, up front and directly from the user, to cover the + // complete cost of the transfer. Any additional fees provided in the XCM program are + // refunded to the beneficiary. We only validate the fee here if its provided to make sure + // the XCM program is well formed. Another way to think about this from an XCM perspective + // would be that the user offered to pay X amount in fees, but we charge 0 of that X amount + // (no fee) and refund X to the user. if let Some(fee_asset) = fee_asset { // The fee asset must be the same as the reserve asset. if fee_asset.id != reserve_asset.id || fee_asset.fun > reserve_asset.fun { 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/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index b157ad4356bd..dca5062ab310 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -15,10 +15,7 @@ use snowbridge_pallet_ethereum_client_fixtures::*; use sp_core::{Get, H160, U256}; use sp_keyring::AccountKeyring::*; 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 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/environments/rococo-westend/rococo.zndsl b/bridges/testing/environments/rococo-westend/rococo-bridge.zndsl similarity index 100% rename from bridges/testing/environments/rococo-westend/rococo.zndsl rename to bridges/testing/environments/rococo-westend/rococo-bridge.zndsl diff --git a/bridges/testing/environments/rococo-westend/rococo-start.zndsl b/bridges/testing/environments/rococo-westend/rococo-start.zndsl new file mode 100644 index 000000000000..8c719b010df6 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/rococo-start.zndsl @@ -0,0 +1,8 @@ +Description: Check if the Rococo parachains started producing blocks reliably +Network: ./bridge_hub_westend_local_network.toml +Creds: config + +# ensure that initialization has completed +asset-hub-rococo-collator1: reports block height is at least 10 within 180 seconds +bridge-hub-rococo-collator1: reports block height is at least 10 within 180 seconds + diff --git a/bridges/testing/environments/rococo-westend/spawn.sh b/bridges/testing/environments/rococo-westend/spawn.sh index a0ab00be1444..83b3b0720bb8 100755 --- a/bridges/testing/environments/rococo-westend/spawn.sh +++ b/bridges/testing/environments/rococo-westend/spawn.sh @@ -35,9 +35,11 @@ start_zombienet $TEST_DIR $westend_def westend_dir westend_pid echo if [[ $init -eq 1 ]]; then + run_zndsl ${BASH_SOURCE%/*}/rococo-start.zndsl $rococo_dir + run_zndsl ${BASH_SOURCE%/*}/westend-start.zndsl $westend_dir + rococo_init_log=$logs_dir/rococo-init.log echo -e "Setting up the rococo side of the bridge. Logs available at: $rococo_init_log\n" - westend_init_log=$logs_dir/westend-init.log echo -e "Setting up the westend side of the bridge. Logs available at: $westend_init_log\n" @@ -47,7 +49,6 @@ if [[ $init -eq 1 ]]; then westend_init_pid=$! wait -n $rococo_init_pid $westend_init_pid - $helper_script init-bridge-hub-rococo-local >> $rococo_init_log 2>&1 & rococo_init_pid=$! $helper_script init-bridge-hub-westend-local >> $westend_init_log 2>&1 & diff --git a/bridges/testing/environments/rococo-westend/start_relayer.sh b/bridges/testing/environments/rococo-westend/start_relayer.sh index 9c57e4a6ab6e..150fce035071 100755 --- a/bridges/testing/environments/rococo-westend/start_relayer.sh +++ b/bridges/testing/environments/rococo-westend/start_relayer.sh @@ -29,8 +29,8 @@ messages_relayer_log=$logs_dir/relayer_messages.log echo -e "Starting rococo-westend messages relayer. Logs available at: $messages_relayer_log\n" start_background_process "$helper_script run-messages-relay" $messages_relayer_log messages_relayer_pid -run_zndsl ${BASH_SOURCE%/*}/rococo.zndsl $rococo_dir -run_zndsl ${BASH_SOURCE%/*}/westend.zndsl $westend_dir +run_zndsl ${BASH_SOURCE%/*}/rococo-bridge.zndsl $rococo_dir +run_zndsl ${BASH_SOURCE%/*}/westend-bridge.zndsl $westend_dir eval $__finality_relayer_pid="'$finality_relayer_pid'" eval $__parachains_relayer_pid="'$parachains_relayer_pid'" diff --git a/bridges/testing/environments/rococo-westend/westend.zndsl b/bridges/testing/environments/rococo-westend/westend-bridge.zndsl similarity index 100% rename from bridges/testing/environments/rococo-westend/westend.zndsl rename to bridges/testing/environments/rococo-westend/westend-bridge.zndsl diff --git a/bridges/testing/environments/rococo-westend/westend-start.zndsl b/bridges/testing/environments/rococo-westend/westend-start.zndsl new file mode 100644 index 000000000000..fe587322edb6 --- /dev/null +++ b/bridges/testing/environments/rococo-westend/westend-start.zndsl @@ -0,0 +1,8 @@ +Description: Check if the Westend parachains started producing blocks reliably +Network: ./bridge_hub_westend_local_network.toml +Creds: config + +# ensure that initialization has completed +asset-hub-westend-collator1: reports block height is at least 10 within 180 seconds +bridge-hub-westend-collator1: reports block height is at least 10 within 180 seconds + 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/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 322baaa01498..2dbcf5eb58e9 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -43,8 +43,8 @@ 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::*; @@ -260,8 +260,7 @@ where relay_parent, params.para_id, &mut params.relay_client, - // Use depth 0, to preserve behaviour. - ClaimQueueOffset(0), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET), ) .await .get(0) 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..425151230704 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,13 +20,11 @@ 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}, + vstaging::{ClaimQueueOffset, CoreSelector, DEFAULT_CLAIM_QUEUE_OFFSET}, BlockId, CoreIndex, Hash as RelayHash, Header as RelayHeader, Id as ParaId, OccupiedCoreAssumption, }; diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 94e2304011be..79e620db3bfa 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -20,7 +20,7 @@ use async_trait::async_trait; use codec::Encode; use cumulus_client_pov_recovery::RecoveryKind; use cumulus_primitives_core::{ - relay_chain::{BlockId, BlockNumber, CoreState}, + relay_chain::{vstaging::CoreState, BlockId, BlockNumber}, CumulusDigestItem, InboundDownwardMessage, InboundHrmpMessage, }; use cumulus_relay_chain_interface::{ diff --git a/cumulus/client/network/src/lib.rs b/cumulus/client/network/src/lib.rs index 01ad15bed4da..3b9c0fc81ece 100644 --- a/cumulus/client/network/src/lib.rs +++ b/cumulus/client/network/src/lib.rs @@ -32,8 +32,8 @@ use polkadot_node_primitives::{CollationSecondedSignal, Statement}; use polkadot_node_subsystem::messages::RuntimeApiRequest; use polkadot_parachain_primitives::primitives::HeadData; use polkadot_primitives::{ - CandidateReceipt, CompactStatement, Hash as PHash, Id as ParaId, OccupiedCoreAssumption, - SigningContext, UncheckedSigned, + vstaging::CandidateReceiptV2 as CandidateReceipt, CompactStatement, Hash as PHash, + Id as ParaId, OccupiedCoreAssumption, SigningContext, UncheckedSigned, }; use codec::{Decode, DecodeAll, Encode}; @@ -79,7 +79,7 @@ impl Decode for BlockAnnounceData { let relay_parent = match PHash::decode(input) { Ok(p) => p, // For being backwards compatible, we support missing relay-chain parent. - Err(_) => receipt.descriptor.relay_parent, + Err(_) => receipt.descriptor.relay_parent(), }; Ok(Self { receipt, statement, relay_parent }) @@ -108,7 +108,7 @@ impl BlockAnnounceData { return Err(Validation::Failure { disconnect: true }) } - if HeadData(encoded_header).hash() != self.receipt.descriptor.para_head { + if HeadData(encoded_header).hash() != self.receipt.descriptor.para_head() { tracing::debug!( target: LOG_TARGET, "Receipt para head hash doesn't match the hash of the header in the block announcement", @@ -302,7 +302,7 @@ where } .map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?; - Ok(candidate_receipts.into_iter().map(|cr| cr.descriptor.para_head)) + Ok(candidate_receipts.into_iter().map(|cr| cr.descriptor.para_head())) } /// Handle a block announcement with empty data (no statement) attached to it. @@ -399,7 +399,7 @@ where return Ok(e) } - let relay_parent = block_announce_data.receipt.descriptor.relay_parent; + let relay_parent = block_announce_data.receipt.descriptor.relay_parent(); relay_chain_interface .wait_for_block(relay_parent) diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index 4b3473645210..cccb710bf18f 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -26,10 +26,11 @@ use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt use parking_lot::Mutex; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_primitives::{ + vstaging::{CommittedCandidateReceiptV2, CoreState}, BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorPair, - CommittedCandidateReceipt, CoreState, Hash as PHash, HeadData, InboundDownwardMessage, - InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex, - SigningContext, ValidationCodeHash, ValidatorId, + CommittedCandidateReceipt, Hash as PHash, HeadData, InboundDownwardMessage, InboundHrmpMessage, + OccupiedCoreAssumption, PersistedValidationData, SessionIndex, SigningContext, + ValidationCodeHash, ValidatorId, }; use polkadot_test_client::{ Client as PClient, ClientBlockImportExt, DefaultTestClientBuilderExt, FullBackend as PBackend, @@ -166,7 +167,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: PHash, _: ParaId, - ) -> RelayChainResult> { + ) -> RelayChainResult> { if self.data.lock().runtime_version >= RuntimeApiRequest::CANDIDATES_PENDING_AVAILABILITY_RUNTIME_REQUIREMENT { @@ -174,7 +175,7 @@ impl RelayChainInterface for DummyRelayChainInterface { } if self.data.lock().has_pending_availability { - Ok(Some(dummy_candidate())) + Ok(Some(dummy_candidate().into())) } else { Ok(None) } @@ -184,7 +185,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: PHash, _: ParaId, - ) -> RelayChainResult> { + ) -> RelayChainResult> { if self.data.lock().runtime_version < RuntimeApiRequest::CANDIDATES_PENDING_AVAILABILITY_RUNTIME_REQUIREMENT { @@ -192,7 +193,7 @@ impl RelayChainInterface for DummyRelayChainInterface { } if self.data.lock().has_pending_availability { - Ok(vec![dummy_candidate()]) + Ok(vec![dummy_candidate().into()]) } else { Ok(vec![]) } @@ -320,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, @@ -412,7 +413,7 @@ async fn make_gossip_message_and_header( validation_code_hash: ValidationCodeHash::from(PHash::random()), }, }; - let statement = Statement::Seconded(candidate_receipt); + let statement = Statement::Seconded(candidate_receipt.into()); let signed = SignedFullStatement::sign( &keystore, statement, @@ -525,7 +526,7 @@ fn legacy_block_announce_data_handling() { let block_data = BlockAnnounceData::decode(&mut &data[..]).expect("Decoding works from legacy works"); - assert_eq!(receipt.descriptor.relay_parent, block_data.relay_parent); + assert_eq!(receipt.descriptor.relay_parent(), block_data.relay_parent); let data = block_data.encode(); LegacyBlockAnnounceData::decode(&mut &data[..]).expect("Decoding works"); @@ -600,7 +601,8 @@ async fn check_statement_seconded() { erasure_root: PHash::random(), signature: sp_core::sr25519::Signature::default().into(), validation_code_hash: ValidationCodeHash::from(PHash::random()), - }, + } + .into(), }, statement: signed_statement.convert_payload().into(), relay_parent, diff --git a/cumulus/client/parachain-inherent/src/mock.rs b/cumulus/client/parachain-inherent/src/mock.rs index a3f881e6ef9d..950cba2aaa7d 100644 --- a/cumulus/client/parachain-inherent/src/mock.rs +++ b/cumulus/client/parachain-inherent/src/mock.rs @@ -45,6 +45,7 @@ pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; /// in addition to the messages themselves, you must provide some information about /// your parachain's configuration in order to mock the MQC heads properly. /// See [`MockXcmConfig`] for more information +#[derive(Default)] pub struct MockValidationDataInherentDataProvider { /// The current block number of the local block chain (the parachain). pub current_para_block: u32, diff --git a/cumulus/client/pov-recovery/src/lib.rs b/cumulus/client/pov-recovery/src/lib.rs index 043cba12d193..87349aef0c93 100644 --- a/cumulus/client/pov-recovery/src/lib.rs +++ b/cumulus/client/pov-recovery/src/lib.rs @@ -56,7 +56,11 @@ use polkadot_node_primitives::{PoV, POV_BOMB_LIMIT}; use polkadot_node_subsystem::messages::{AvailabilityRecoveryMessage, RuntimeApiRequest}; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::{ - CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex, + vstaging::{ + CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, + }, + Id as ParaId, SessionIndex, }; use cumulus_primitives_core::ParachainBlockData; diff --git a/cumulus/client/pov-recovery/src/tests.rs b/cumulus/client/pov-recovery/src/tests.rs index 94dec32485cc..91b462e06bf8 100644 --- a/cumulus/client/pov-recovery/src/tests.rs +++ b/cumulus/client/pov-recovery/src/tests.rs @@ -18,7 +18,7 @@ use super::*; use assert_matches::assert_matches; use codec::{Decode, Encode}; use cumulus_primitives_core::relay_chain::{ - BlockId, CandidateCommitments, CandidateDescriptor, CoreIndex, CoreState, + vstaging::CoreState, BlockId, CandidateCommitments, CandidateDescriptor, CoreIndex, }; use cumulus_relay_chain_interface::{ InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PHash, PHeader, @@ -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, @@ -532,7 +532,8 @@ fn make_candidate_chain(candidate_number_range: Range) -> Vec Result>, sp_api::ApiError> { + ) -> Result< + Vec>, + sp_api::ApiError, + > { Ok(self.rpc_client.parachain_host_availability_cores(at).await?) } @@ -212,8 +215,11 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn candidate_pending_availability( &self, at: Hash, - para_id: ParaId, - ) -> Result>, sp_api::ApiError> { + para_id: cumulus_primitives_core::ParaId, + ) -> Result< + Option>, + sp_api::ApiError, + > { Ok(self .rpc_client .parachain_host_candidate_pending_availability(at, para_id) @@ -223,7 +229,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn candidate_events( &self, at: Hash, - ) -> Result>, sp_api::ApiError> { + ) -> Result>, sp_api::ApiError> { Ok(self.rpc_client.parachain_host_candidate_events(at).await?) } @@ -266,7 +272,8 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn on_chain_votes( &self, at: Hash, - ) -> Result>, sp_api::ApiError> { + ) -> Result>, sp_api::ApiError> + { Ok(self.rpc_client.parachain_host_on_chain_votes(at).await?) } @@ -437,8 +444,11 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn candidates_pending_availability( &self, at: Hash, - para_id: ParaId, - ) -> Result>, sp_api::ApiError> { + para_id: cumulus_primitives_core::ParaId, + ) -> Result< + Vec>, + sp_api::ApiError, + > { Ok(self .rpc_client .parachain_host_candidates_pending_availability(at, para_id) 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/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index f53cdeffea94..0e2f6c054c40 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -18,8 +18,9 @@ use async_trait::async_trait; use core::time::Duration; use cumulus_primitives_core::{ relay_chain::{ - CommittedCandidateReceipt, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, - OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, Hash as RelayHash, + Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, + ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index d8e5abaddc6b..d7785d92c73a 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -32,13 +32,18 @@ use codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain::{ - async_backing::{AsyncBackingParams, BackingState}, - slashing, ApprovalVotingParams, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, - ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, - InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing::AsyncBackingParams, + slashing, + vstaging::{ + async_backing::BackingState, CandidateEvent, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + ApprovalVotingParams, BlockNumber, CandidateCommitments, CandidateHash, CoreIndex, + DisputeState, ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, + InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, PvfCheckStatement, SessionIndex, + SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 92dc64371f34..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; @@ -417,7 +414,7 @@ pub struct BuildNetworkParams< pub net_config: sc_network::config::FullNetworkConfiguration::Hash, Network>, pub client: Arc, - pub transaction_pool: Arc>, + pub transaction_pool: Arc>, pub para_id: ParaId, pub relay_chain_interface: RCInterface, pub spawn_handle: SpawnTaskHandle, @@ -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/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 66429625d5bf..3cb0394c4b95 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -121,3 +121,5 @@ try-runtime = [ "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] + +experimental-ump-signals = [] diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 21af35fe3de3..39fc8321a072 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::{ @@ -193,20 +193,46 @@ pub mod ump_constants { /// Trait for selecting the next core to build the candidate for. pub trait SelectCore { - fn select_core_for_child() -> (CoreSelector, ClaimQueueOffset); + /// Core selector information for the current block. + fn selected_core() -> (CoreSelector, ClaimQueueOffset); + /// Core selector information for the next block. + fn select_next_core() -> (CoreSelector, ClaimQueueOffset); } /// The default core selection policy. pub struct DefaultCoreSelector(PhantomData); impl SelectCore for DefaultCoreSelector { - fn select_core_for_child() -> (CoreSelector, ClaimQueueOffset) { + fn selected_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = frame_system::Pallet::::block_number().into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)) + } + + fn select_next_core() -> (CoreSelector, ClaimQueueOffset) { let core_selector: U256 = (frame_system::Pallet::::block_number() + One::one()).into(); (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)) } } +/// Core selection policy that builds on claim queue offset 1. +pub struct LookaheadCoreSelector(PhantomData); + +impl SelectCore for LookaheadCoreSelector { + fn selected_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = frame_system::Pallet::::block_number().into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(1)) + } + + fn select_next_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = (frame_system::Pallet::::block_number() + One::one()).into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(1)) + } +} + #[frame_support::pallet] pub mod pallet { use super::*; @@ -365,6 +391,11 @@ pub mod pallet { UpwardMessages::::put(&up[..num as usize]); *up = up.split_off(num as usize); + // Send the core selector UMP signal. This is experimental until relay chain + // validators are upgraded to handle ump signals. + #[cfg(feature = "experimental-ump-signals")] + Self::send_ump_signal(); + // If the total size of the pending messages is less than the threshold, // we decrease the fee factor, since the queue is less congested. // This makes delivery of new messages cheaper. @@ -1397,9 +1428,9 @@ impl Pallet { } } - /// Returns the core selector. + /// Returns the core selector for the next block. pub fn core_selector() -> (CoreSelector, ClaimQueueOffset) { - T::SelectCore::select_core_for_child() + T::SelectCore::select_next_core() } /// Set a custom head data that should be returned as result of `validate_block`. @@ -1418,6 +1449,20 @@ impl Pallet { CustomValidationHeadData::::put(head_data); } + /// Send the ump signals + #[cfg(feature = "experimental-ump-signals")] + fn send_ump_signal() { + use cumulus_primitives_core::relay_chain::vstaging::{UMPSignal, UMP_SEPARATOR}; + + UpwardMessages::::mutate(|up| { + up.push(UMP_SEPARATOR); + + // Send the core selector signal. + let core_selector = T::SelectCore::selected_core(); + up.push(UMPSignal::SelectCore(core_selector.0, core_selector.1).encode()); + }); + } + /// Open HRMP channel for using it in benchmarks or tests. /// /// The caller assumes that the pallet will accept regular outbound message to the sibling @@ -1582,7 +1627,11 @@ impl InspectMessageQueues for Pallet { .map(|encoded_message| VersionedXcm::<()>::decode(&mut &encoded_message[..]).unwrap()) .collect(); - vec![(VersionedLocation::V4(Parent.into()), messages)] + if messages.is_empty() { + vec![] + } else { + vec![(VersionedLocation::from(Location::parent()), messages)] + } } } 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/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 23223627ebca..2b65dd6a9216 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -25,6 +25,8 @@ use frame_support::{assert_ok, parameter_types, weights::Weight}; use frame_system::RawOrigin; use hex_literal::hex; use rand::Rng; +#[cfg(feature = "experimental-ump-signals")] +use relay_chain::vstaging::{UMPSignal, UMP_SEPARATOR}; use relay_chain::HrmpChannelId; use sp_core::H256; @@ -583,7 +585,25 @@ fn send_upward_message_num_per_candidate() { }, || { let v = UpwardMessages::::get(); - assert_eq!(v, vec![b"Mr F was here".to_vec()]); + #[cfg(feature = "experimental-ump-signals")] + { + assert_eq!( + v, + vec![ + b"Mr F was here".to_vec(), + UMP_SEPARATOR, + UMPSignal::SelectCore( + CoreSelector(1), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET) + ) + .encode() + ] + ); + } + #[cfg(not(feature = "experimental-ump-signals"))] + { + assert_eq!(v, vec![b"Mr F was here".to_vec()]); + } }, ) .add_with_post_test( @@ -594,7 +614,25 @@ fn send_upward_message_num_per_candidate() { }, || { let v = UpwardMessages::::get(); - assert_eq!(v, vec![b"message 2".to_vec()]); + #[cfg(feature = "experimental-ump-signals")] + { + assert_eq!( + v, + vec![ + b"message 2".to_vec(), + UMP_SEPARATOR, + UMPSignal::SelectCore( + CoreSelector(2), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET) + ) + .encode() + ] + ); + } + #[cfg(not(feature = "experimental-ump-signals"))] + { + assert_eq!(v, vec![b"message 2".to_vec()]); + } }, ); } @@ -620,7 +658,24 @@ fn send_upward_message_relay_bottleneck() { || { // The message won't be sent because there is already one message in queue. let v = UpwardMessages::::get(); - assert!(v.is_empty()); + #[cfg(feature = "experimental-ump-signals")] + { + assert_eq!( + v, + vec![ + UMP_SEPARATOR, + UMPSignal::SelectCore( + CoreSelector(1), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET) + ) + .encode() + ] + ); + } + #[cfg(not(feature = "experimental-ump-signals"))] + { + assert!(v.is_empty()); + } }, ) .add_with_post_test( @@ -628,7 +683,25 @@ fn send_upward_message_relay_bottleneck() { || { /* do nothing within block */ }, || { let v = UpwardMessages::::get(); - assert_eq!(v, vec![vec![0u8; 8]]); + #[cfg(feature = "experimental-ump-signals")] + { + assert_eq!( + v, + vec![ + vec![0u8; 8], + UMP_SEPARATOR, + UMPSignal::SelectCore( + CoreSelector(2), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET) + ) + .encode() + ] + ); + } + #[cfg(not(feature = "experimental-ump-signals"))] + { + assert_eq!(v, vec![vec![0u8; 8]]); + } }, ); } @@ -1172,7 +1245,25 @@ fn ump_fee_factor_increases_and_decreases() { || { // Factor decreases in `on_finalize`, but only if we are below the threshold let messages = UpwardMessages::::get(); - assert_eq!(messages, vec![b"Test".to_vec()]); + #[cfg(feature = "experimental-ump-signals")] + { + assert_eq!( + messages, + vec![ + b"Test".to_vec(), + UMP_SEPARATOR, + UMPSignal::SelectCore( + CoreSelector(1), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET) + ) + .encode() + ] + ); + } + #[cfg(not(feature = "experimental-ump-signals"))] + { + assert_eq!(messages, vec![b"Test".to_vec()]); + } assert_eq!( UpwardDeliveryFeeFactor::::get(), FixedU128::from_rational(105, 100) @@ -1186,10 +1277,28 @@ fn ump_fee_factor_increases_and_decreases() { }, || { let messages = UpwardMessages::::get(); - assert_eq!( - messages, - vec![b"This message will be enough to increase the fee factor".to_vec(),] - ); + #[cfg(feature = "experimental-ump-signals")] + { + assert_eq!( + messages, + vec![ + b"This message will be enough to increase the fee factor".to_vec(), + UMP_SEPARATOR, + UMPSignal::SelectCore( + CoreSelector(2), + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET) + ) + .encode() + ] + ); + } + #[cfg(not(feature = "experimental-ump-signals"))] + { + assert_eq!( + messages, + vec![b"This message will be enough to increase the fee factor".to_vec()] + ); + } // Now the delivery fee factor is decreased, since we are below the threshold assert_eq!(UpwardDeliveryFeeFactor::::get(), FixedU128::from_u32(1)); }, diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index c4c8440e5187..2c531c39accd 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -33,7 +33,7 @@ use frame_support::traits::{ExecuteBlock, ExtrinsicCall, Get, IsSubType}; use sp_core::storage::{ChildInfo, StateVersion}; use sp_externalities::{set_and_run_with_externalities, Externalities}; use sp_io::KillStorageResult; -use sp_runtime::traits::{Block as BlockT, Extrinsic, HashingFor, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, ExtrinsicLike, HashingFor, Header as HeaderT}; use sp_trie::{MemoryDB, ProofSizeProvider}; use trie_recorder::SizeOnlyRecorderProvider; @@ -96,7 +96,7 @@ pub fn validate_block< ) -> ValidationResult where B::Extrinsic: ExtrinsicCall, - ::Call: IsSubType>, + ::Call: IsSubType>, { let block_data = codec::decode_from_bytes::>(block_data) .expect("Invalid parachain block data"); @@ -240,16 +240,13 @@ fn extract_parachain_inherent_data( ) -> &ParachainInherentData where B::Extrinsic: ExtrinsicCall, - ::Call: IsSubType>, + ::Call: IsSubType>, { block .extrinsics() .iter() // Inherents are at the front of the block and are unsigned. - // - // If `is_signed` is returning `None`, we keep it safe and assume that it is "signed". - // We are searching for unsigned transactions anyway. - .take_while(|e| !e.is_signed().unwrap_or(true)) + .take_while(|e| e.is_bare()) .filter_map(|e| e.call().is_sub_type()) .find_map(|c| match c { crate::Call::set_validation_data { data: validation_data } => Some(validation_data), 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/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/coretime-polkadot.json b/cumulus/parachains/chain-specs/coretime-polkadot.json index 806231db7646..e4f947d2afc9 100644 --- a/cumulus/parachains/chain-specs/coretime-polkadot.json +++ b/cumulus/parachains/chain-specs/coretime-polkadot.json @@ -10,7 +10,9 @@ "/dns4/coretime-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWFJ2yBTKFKYwgKUjfY3F7XfaxHV8hY6fbJu5oMkpP7wZ9", "/dns4/coretime-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWCy5pToLafcQzPHn5kadxAftmF6Eh8ZJGPXhSeXSUDfjv", "/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-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" ], "telemetryEndpoints": null, "protocolId": null, @@ -91,4 +93,4 @@ "childrenDefault": {} } } -} \ No newline at end of file +} diff --git a/cumulus/parachains/common/src/genesis_config_helpers.rs b/cumulus/parachains/common/src/genesis_config_helpers.rs deleted file mode 100644 index cd98c3a729d2..000000000000 --- a/cumulus/parachains/common/src/genesis_config_helpers.rs +++ /dev/null @@ -1,46 +0,0 @@ -// 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. - -//! Some common helpers for declaring runtime's presets - -use crate::{AccountId, Signature}; -#[cfg(not(feature = "std"))] -use alloc::format; -use sp_core::{Pair, Public}; -use sp_runtime::traits::{IdentifyAccount, Verify}; - -/// Helper function to generate a crypto pair from seed. -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{seed}"), None) - .expect("static values are valid; qed") - .public() -} - -type AccountPublic = ::Signer; - -/// Helper function to generate an account id from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - -/// Generate collator keys from seed. -/// -/// This function's return type must always match the session keys of the chain in tuple format. -pub fn get_collator_keys_from_seed(seed: &str) -> ::Public { - get_from_seed::(seed) -} diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index 60040fda9928..3cffb69daac3 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -17,7 +17,6 @@ extern crate alloc; -pub mod genesis_config_helpers; pub mod impls; pub mod message_queue; pub mod xcm_config; 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 51ce5b180056..25796e7d64b4 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 @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Cumulus 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 5b70ed490c63..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 @@ -15,13 +15,14 @@ // Substrate use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, - 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}; @@ -29,7 +30,7 @@ pub const PARA_ID: u32 = 1000; pub const ED: Balance = testnet_parachains_constants::rococo::currency::EXISTENTIAL_DEPOSIT; parameter_types! { - pub AssetHubRococoAssetOwner: AccountId = get_account_id_from_seed::("Alice"); + pub AssetHubRococoAssetOwner: AccountId = Keyring::Alice.to_account_id(); } pub fn genesis() -> Storage { @@ -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 d32f98321706..8e423ebbf9c2 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 @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Cumulus 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 a9cfcda0dacd..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 @@ -15,14 +15,14 @@ // Substrate use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, - 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}; @@ -31,7 +31,7 @@ pub const ED: Balance = testnet_parachains_constants::westend::currency::EXISTEN pub const USDT_ED: Balance = 70_000; parameter_types! { - pub AssetHubWestendAssetOwner: AccountId = get_account_id_from_seed::("Alice"); + pub AssetHubWestendAssetOwner: AccountId = Keyring::Alice.to_account_id(); } pub fn genesis() -> Storage { @@ -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 266d743ca0c2..231265085eda 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 @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Polkadot Dependencies 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 b9c0c01101c6..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 @@ -14,14 +14,15 @@ // limitations under the License. // Substrate -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + 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; @@ -60,11 +61,11 @@ pub fn genesis() -> Storage { ..Default::default() }, bridge_westend_grandpa: bridge_hub_rococo_runtime::BridgeWestendGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), ..Default::default() }, bridge_westend_messages: bridge_hub_rococo_runtime::BridgeWestendMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), ..Default::default() }, xcm_over_bridge_hub_westend: bridge_hub_rococo_runtime::XcmOverBridgeHubWestendConfig { @@ -72,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 88d7348f50f2..8292e132809c 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 @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Polkadot Dependencies 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 3ffe3d86b2ac..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 @@ -14,14 +14,15 @@ // limitations under the License. // Substrate -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + 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; @@ -60,11 +61,11 @@ pub fn genesis() -> Storage { ..Default::default() }, bridge_rococo_grandpa: bridge_hub_westend_runtime::BridgeRococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), ..Default::default() }, bridge_rococo_messages: bridge_hub_westend_runtime::BridgeRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), ..Default::default() }, xcm_over_bridge_hub_rococo: bridge_hub_westend_runtime::XcmOverBridgeHubRococoConfig { @@ -72,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/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 9e6b14b58598..743cd7dc54a2 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 @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Polkadot diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs index 2c34b7e96f5e..63510d233d2c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/genesis.rs @@ -15,11 +15,12 @@ // Substrate use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::{AccountId, Balance}; use penpal_runtime::xcm_config::{LocalReservableFromAssetHub, RelayLocation, UsdtFromAssetHub}; @@ -30,7 +31,7 @@ pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; pub const USDT_ED: Balance = 70_000; parameter_types! { - pub PenpalSudoAccount: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalSudoAccount: AccountId = Keyring::Alice.to_account_id(); pub PenpalAssetOwner: AccountId = PenpalSudoAccount::get(); } 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 9376687947e6..6db1263df8c7 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-authority-discovery = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs index 9cb25b403600..3d8b5b1a500f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/genesis.rs @@ -18,14 +18,15 @@ use sc_consensus_grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Polkadot use polkadot_primitives::{AssignmentId, ValidatorId}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_host_config, validators, + accounts, build_genesis_storage, get_host_config, validators, }; use parachains_common::Balance; use rococo_runtime_constants::currency::UNITS as ROC; @@ -82,9 +83,7 @@ pub fn genesis() -> Storage { epoch_config: rococo_runtime::BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, - sudo: rococo_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), - }, + sudo: rococo_runtime::SudoConfig { key: Some(Keyring::Alice.to_account_id()) }, configuration: rococo_runtime::ConfigurationConfig { config: get_host_config() }, registrar: rococo_runtime::RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 981ee5c88b4e..23edaf6bfe65 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -21,6 +21,7 @@ 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 } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index c6b8889730e5..e2757f8b9a35 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -25,11 +25,9 @@ use sc_consensus_grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; -use sp_core::{sr25519, storage::Storage, Pair, Public}; -use sp_runtime::{ - traits::{AccountIdConversion, IdentifyAccount, Verify}, - BuildStorage, MultiSignature, -}; +use sp_core::storage::Storage; +use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; +use sp_runtime::{traits::AccountIdConversion, BuildStorage}; // Polakdot use parachains_common::BlockNumber; @@ -43,14 +41,13 @@ 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; /// The default XCM version to set in genesis config. pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -type AccountPublic = ::Signer; - // (trust-backed) Asset registered on AH and reserve-transferred between Parachain and AH pub const RESERVABLE_ASSET_ID: u32 = 1; // ForeignAsset registered on AH and teleported between Penpal and AH @@ -59,44 +56,29 @@ 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(); } -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - pub fn get_host_config() -> HostConfiguration { HostConfiguration { max_upward_queue_count: 10, @@ -130,34 +112,10 @@ pub mod accounts { use super::*; pub const ALICE: &str = "Alice"; pub const BOB: &str = "Bob"; - pub const CHARLIE: &str = "Charlie"; - pub const DAVE: &str = "Dave"; - pub const EVE: &str = "Eve"; - pub const FERDIE: &str = "Ferdie"; - pub const ALICE_STASH: &str = "Alice//stash"; - pub const BOB_STASH: &str = "Bob//stash"; - pub const CHARLIE_STASH: &str = "Charlie//stash"; - pub const DAVE_STASH: &str = "Dave//stash"; - pub const EVE_STASH: &str = "Eve//stash"; - pub const FERDIE_STASH: &str = "Ferdie//stash"; - pub const FERDIE_BEEFY: &str = "Ferdie//stash"; pub const DUMMY_EMPTY: &str = "JohnDoe"; pub fn init_balances() -> Vec { - vec![ - get_account_id_from_seed::(ALICE), - get_account_id_from_seed::(BOB), - get_account_id_from_seed::(CHARLIE), - get_account_id_from_seed::(DAVE), - get_account_id_from_seed::(EVE), - get_account_id_from_seed::(FERDIE), - get_account_id_from_seed::(ALICE_STASH), - get_account_id_from_seed::(BOB_STASH), - get_account_id_from_seed::(CHARLIE_STASH), - get_account_id_from_seed::(DAVE_STASH), - get_account_id_from_seed::(EVE_STASH), - get_account_id_from_seed::(FERDIE_STASH), - ] + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect() } } @@ -166,16 +124,15 @@ pub mod collators { pub fn invulnerables() -> Vec<(AccountId, AuraId)> { vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - (get_account_id_from_seed::("Bob"), get_from_seed::("Bob")), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ] } } pub mod validators { + use sp_consensus_beefy::test_utils::Keyring; + use super::*; pub fn initial_authorities() -> Vec<( @@ -188,16 +145,15 @@ pub mod validators { AuthorityDiscoveryId, BeefyId, )> { - let seed = "Alice"; vec![( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::Alice.to_account_id(), + BabeId::from(Sr25519Keyring::Alice.public()), + GrandpaId::from(Ed25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Alice.public()), + AssignmentId::from(Sr25519Keyring::Alice.public()), + AuthorityDiscoveryId::from(Sr25519Keyring::Alice.public()), + BeefyId::from(Keyring::::Alice.public()), )] } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 578bca84ce5a..b776cafb2545 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -403,3 +403,343 @@ 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 ) => { + $crate::macros::paste::paste! { + use frame_support::{dispatch::RawOrigin, traits::fungible}; + use sp_runtime::AccountId32; + use xcm::prelude::*; + use xcm_runtime_apis::dry_run::runtime_decl_for_dry_run_api::DryRunApiV1; + + let who = AccountId32::new([1u8; 32]); + let transfer_amount = 10_000_000_000_000u128; + let initial_balance = transfer_amount * 10; + + // Bridge setup. + $sender_asset_hub::force_xcm_version($destination, XCM_VERSION); + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + + <$sender_asset_hub as TestExt>::execute_with(|| { + type Runtime = <$sender_asset_hub as Chain>::Runtime; + type RuntimeCall = <$sender_asset_hub as Chain>::RuntimeCall; + type OriginCaller = <$sender_asset_hub as Chain>::OriginCaller; + type Balances = <$sender_asset_hub as [<$sender_asset_hub Pallet>]>::Balances; + + // Give some initial funds. + >::set_balance(&who, initial_balance); + + let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::from($destination)), + beneficiary: Box::new(VersionedLocation::from(Junction::AccountId32 { + id: who.clone().into(), + network: None, + })), + assets: Box::new(VersionedAssets::from(vec![ + (Parent, transfer_amount).into(), + ])), + fee_asset_item: 0, + weight_limit: Unlimited, + }); + let result = Runtime::dry_run_call(OriginCaller::system(RawOrigin::Signed(who)), call).unwrap(); + // We assert the dry run succeeds and sends only one message to the local bridge hub. + assert!(result.execution_result.is_ok()); + assert_eq!(result.forwarded_xcms.len(), 1); + assert_eq!(result.forwarded_xcms[0].0, VersionedLocation::from(Location::new(1, [Parachain($sender_bridge_hub::para_id().into())]))); + }); + } + }; +} + +#[macro_export] +macro_rules! test_xcm_fee_querying_apis_work_for_asset_hub { + ( $asset_hub:ty ) => { + $crate::macros::paste::paste! { + use emulated_integration_tests_common::USDT_ID; + use xcm_runtime_apis::fees::{Error as XcmPaymentApiError, runtime_decl_for_xcm_payment_api::XcmPaymentApiV1}; + + $asset_hub::execute_with(|| { + // Setup a pool between USDT and WND. + type RuntimeOrigin = <$asset_hub as Chain>::RuntimeOrigin; + type Assets = <$asset_hub as [<$asset_hub Pallet>]>::Assets; + type AssetConversion = <$asset_hub as [<$asset_hub Pallet>]>::AssetConversion; + let wnd = Location::new(1, []); + let usdt = Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]); + let sender = [<$asset_hub Sender>]::get(); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(sender.clone()), + Box::new(wnd.clone()), + Box::new(usdt.clone()), + )); + + type Runtime = <$asset_hub as Chain>::Runtime; + 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())), + ]); + + let program = Xcm::<()>::builder() + .withdraw_asset((Parent, 100u128)) + .buy_execution((Parent, 10u128), Unlimited) + .deposit_asset(All, [0u8; 32]) + .build(); + let weight = Runtime::query_xcm_weight(VersionedXcm::from(program)).unwrap(); + let fee_in_wnd = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(wnd.clone()))).unwrap(); + // Assets not in a pool don't work. + assert!(Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(1)])))).is_err()); + let fee_in_usdt_fail = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(usdt.clone()))); + // Weight to asset fee fails because there's not enough asset in the pool. + // We just created it, there's none. + assert_eq!(fee_in_usdt_fail, Err(XcmPaymentApiError::AssetNotFound)); + // We add some. + assert_ok!(Assets::mint( + RuntimeOrigin::signed(sender.clone()), + USDT_ID.into(), + sender.clone().into(), + 5_000_000_000_000 + )); + // We make 1 WND = 4 USDT. + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(sender.clone()), + Box::new(wnd), + Box::new(usdt.clone()), + 1_000_000_000_000, + 4_000_000_000_000, + 0, + 0, + sender.into() + )); + // Now it works. + let fee_in_usdt = Runtime::query_weight_to_asset_fee(weight, VersionedAssetId::from(AssetId(usdt))); + assert_ok!(fee_in_usdt); + assert!(fee_in_usdt.unwrap() > fee_in_wnd); + }); + } + }; +} 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..9125c976525e 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 }, 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 }, ])) } 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 f66a5f1d5fe7..3d40db6b03ab 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 @@ -16,6 +16,7 @@ assert_matches = { workspace = true } # Substrate sp-runtime = { workspace = true } +sp-core = { workspace = true } frame-support = { workspace = true } pallet-balances = { workspace = true } pallet-assets = { 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 0e43108a417b..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; @@ -36,8 +36,8 @@ mod imports { pub use asset_test_utils::xcm_helpers; pub use emulated_integration_tests_common::{ accounts::DUMMY_EMPTY, - get_account_id_from_seed, test_parachain_is_trusted_teleporter, - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, + test_parachain_is_trusted_teleporter, test_parachain_is_trusted_teleporter_for_relay, + test_relay_is_trusted_teleporter, test_xcm_fee_querying_apis_work_for_asset_hub, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, TestArgs, TestContext, TestExt, 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..baec7d20f415 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 @@ -163,7 +163,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 +171,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 +293,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 +301,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 +455,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 +464,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(), 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 8aad4b392b2c..698ef2c9e792 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 sp_core::{crypto::get_public_from_string_or_panic, sr25519}; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -1042,7 +1043,8 @@ fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { ); // Beneficiary is a new (empty) account - let receiver = get_account_id_from_seed::(DUMMY_EMPTY); + let receiver: sp_runtime::AccountId32 = + get_public_from_string_or_panic::(DUMMY_EMPTY).into(); // Init values for Asset Hub let penpal_location_as_seen_by_ahr = AssetHubRococo::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_location_as_seen_by_ahr); @@ -1597,7 +1599,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/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index ac0c90ba198d..d9b32eaa357e 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -386,3 +386,8 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { ); }); } + +#[test] +fn xcm_fee_querying_apis_work() { + test_xcm_fee_querying_apis_work_for_asset_hub!(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..69111d38bcac 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 @@ -71,11 +71,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 +111,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 +171,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); 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 6b50b6f473ed..7117124b1d1f 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 @@ -16,7 +16,6 @@ assert_matches = { workspace = true } # Substrate sp-runtime = { workspace = true } -sp-keyring = { workspace = true } sp-core = { workspace = true } frame-metadata-hash-extension = { workspace = true, default-features = true } frame-support = { workspace = true } @@ -32,11 +31,13 @@ pallet-asset-tx-payment = { workspace = true } # Polkadot 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 +assets-common = { workspace = true } parachains-common = { workspace = true, default-features = true } asset-test-utils = { workspace = true, default-features = true } cumulus-pallet-xcmp-queue = { 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 d0016b5a1b15..3cca99fbfe5c 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,15 +26,18 @@ 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 pub use asset_test_utils::xcm_helpers; pub use emulated_integration_tests_common::{ accounts::DUMMY_EMPTY, - get_account_id_from_seed, test_parachain_is_trusted_teleporter, - test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, + test_parachain_is_trusted_teleporter, test_parachain_is_trusted_teleporter_for_relay, + test_relay_is_trusted_teleporter, test_xcm_fee_querying_apis_work_for_asset_hub, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, Test, TestArgs, TestContext, TestExt, @@ -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, 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..a0fc82fba6ef 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 @@ -163,7 +163,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 +171,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 +293,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 +301,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 +456,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 +465,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(), @@ -819,3 +819,88 @@ 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); } + +// ============================================================================================== +// ==== 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 transport 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 transport 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 0100e8e34ef3..558eab13e5c7 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,7 +13,8 @@ // 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}; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -650,10 +651,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); @@ -663,10 +662,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); @@ -721,10 +718,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 @@ -734,10 +729,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 @@ -783,10 +775,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); @@ -796,10 +786,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); @@ -855,10 +843,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 @@ -868,10 +854,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 @@ -949,17 +933,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); @@ -973,14 +950,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 @@ -1043,7 +1016,8 @@ fn reserve_transfer_multiple_assets_from_para_to_asset_hub() { ); // Beneficiary is a new (empty) account - let receiver = get_account_id_from_seed::(DUMMY_EMPTY); + let receiver: sp_runtime::AccountId32 = + get_public_from_string_or_panic::(DUMMY_EMPTY).into(); // Init values for Asset Hub let penpal_location_as_seen_by_ahr = AssetHubWestend::sibling_location_of(PenpalA::para_id()); let sov_penpal_on_ahr = @@ -1080,14 +1054,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; @@ -1101,14 +1071,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; @@ -1169,14 +1135,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); @@ -1186,14 +1148,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); @@ -1229,55 +1187,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())], @@ -1308,10 +1222,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); @@ -1326,10 +1238,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. @@ -1369,7 +1278,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; @@ -1381,101 +1290,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; @@ -1521,14 +1344,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); @@ -1538,14 +1356,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); @@ -1601,7 +1413,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..544b05360521 --- /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_asset_claimer(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_asset_claimer(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/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index 1a2821452155..4535fd431990 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -389,3 +389,8 @@ fn pay_xcm_fee_with_some_asset_swapped_for_native() { ); }); } + +#[test] +fn xcm_fee_querying_apis_work() { + test_xcm_fee_querying_apis_work_for_asset_hub!(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..3c53cfb261be --- /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 }, + 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 transport 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..c303e6411d33 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 @@ -32,11 +32,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); 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 86ace7d564e8..9f6fe78a33ee 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 @@ -28,6 +28,7 @@ sp-runtime = { workspace = true } xcm = { workspace = true } pallet-xcm = { workspace = true } xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Bridges pallet-bridge-messages = { 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 e83b28076789..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,10 +22,8 @@ mod imports { // Polkadot pub use xcm::{ - latest::ParentThen, + latest::{ParentThen, ROCOCO_GENESIS_HASH, WESTEND_GENESIS_HASH}, prelude::{AccountId32 as AccountId32Junction, *}, - v4, - v4::NetworkId::Westend as WestendId, }; pub use xcm_executor::traits::TransferType; @@ -33,22 +31,23 @@ mod imports { pub use emulated_integration_tests_common::{ accounts::ALICE, impls::Inspect, - test_parachain_is_trusted_teleporter, test_parachain_is_trusted_teleporter_for_relay, - test_relay_is_trusted_teleporter, + test_dry_run_transfer_across_pk_bridge, test_parachain_is_trusted_teleporter, + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, }, + xcm_helpers::xcm_transact_paid_execution, ASSETS_PALLET_ID, USDT_ID, }; pub use parachains_common::AccountId; pub use rococo_westend_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ asset_hub_rococo_runtime::xcm_config as ahr_xcm_config, - genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, - AssetHubRococoParaPallet as AssetHubRococoPallet, + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, }, asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, + AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_rococo_emulated_chain::{ genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoExistentialDeposit, @@ -80,6 +79,7 @@ mod imports { RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, }; + pub const ASSET_ID: u32 = 1; pub const ASSET_MIN_BALANCE: u128 = 1000; } 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 11930798da44..33ab1e70b97b 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 @@ -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 @@ -113,14 +113,8 @@ fn send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah( } #[test] -/// Test transfer of ROC, USDT and wETH from AssetHub Rococo to AssetHub Westend. -/// -/// This mix of assets should cover the whole range: -/// - native assets: ROC, -/// - trust-based assets: USDT (exists only on Rococo, Westend gets it from Rococo over bridge), -/// - foreign asset / bridged asset (other bridge / Snowfork): wETH (bridged from Ethereum to Rococo -/// over Snowbridge, then bridged over to Westend through this bridge). -fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { +/// Test transfer of ROC from AssetHub Rococo to AssetHub Westend. +fn send_roc_from_asset_hub_rococo_to_asset_hub_westend() { let amount = ASSET_HUB_ROCOCO_ED * 1_000_000; let sender = AssetHubRococoSender::get(); let receiver = AssetHubWestendReceiver::get(); @@ -128,13 +122,10 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { let bridged_roc_at_asset_hub_westend = bridged_roc_at_ah_westend(); create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true); - set_up_pool_with_wnd_on_ah_westend(bridged_roc_at_asset_hub_westend.clone()); + set_up_pool_with_wnd_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true); - //////////////////////////////////////////////////////////// - // Let's first send over just some ROCs as a simple example - //////////////////////////////////////////////////////////// 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 = @@ -146,8 +137,7 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { // send ROCs, use them for fees send_assets_over_bridge(|| { let destination = asset_hub_westend_location(); - let assets: Assets = - (Location::try_from(roc_at_asset_hub_rococo.clone()).unwrap(), amount).into(); + let assets: Assets = (roc_at_asset_hub_rococo.clone(), amount).into(); let fee_idx = 0; assert_ok!(send_assets_from_asset_hub_rococo(destination, assets, fee_idx)); }); @@ -183,84 +173,18 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { assert!(receiver_rocs_after > receiver_rocs_before); // Reserve ROC balance is increased by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount); - - ///////////////////////////////////////////////////////////// - // Now let's send over USDTs + wETH (and pay fees with USDT) - ///////////////////////////////////////////////////////////// - - let usdt_at_asset_hub_rococo = usdt_at_ah_rococo(); - let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend(); - // wETH has same relative location on both Rococo and Westend AssetHubs - let bridged_weth_at_ah = weth_at_asset_hubs(); - - // mint USDT in sender's account (USDT already created in genesis) - AssetHubRococo::mint_asset( - ::RuntimeOrigin::signed(AssetHubRococoAssetOwner::get()), - USDT_ID, - sender.clone(), - amount * 2, - ); - // create wETH at src and dest and prefund sender's account - create_foreign_on_ah_rococo( - bridged_weth_at_ah.clone(), - true, - vec![(sender.clone(), amount * 2)], - ); - create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true); - create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone(), true); - set_up_pool_with_wnd_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone()); - - let receiver_usdts_before = - foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone(), &receiver); - let receiver_weth_before = foreign_balance_on_ah_westend(bridged_weth_at_ah.clone(), &receiver); - - // send USDTs and wETHs - let assets: Assets = vec![ - (usdt_at_asset_hub_rococo.clone(), amount).into(), - (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount).into(), - ] - .into(); - // use USDT for fees - let fee: AssetId = usdt_at_asset_hub_rococo.into(); - - // use the more involved transfer extrinsic - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), - }]); - assert_ok!(AssetHubRococo::execute_with(|| { - ::PolkadotXcm::transfer_assets_using_type_and_then( - ::RuntimeOrigin::signed(sender.into()), - bx!(asset_hub_westend_location().into()), - bx!(assets.into()), - bx!(TransferType::LocalReserve), - bx!(fee.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify hops (also advances the message through the hops) - assert_bridge_hub_rococo_message_accepted(true); - assert_bridge_hub_westend_message_received(); - AssetHubWestend::execute_with(|| { - AssetHubWestend::assert_xcmp_queue_success(None); - }); - - let receiver_usdts_after = - foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend, &receiver); - let receiver_weth_after = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); - - // Receiver's USDT balance is increased by almost `amount` (minus fees) - assert!(receiver_usdts_after > receiver_usdts_before); - assert!(receiver_usdts_after < receiver_usdts_before + amount); - // Receiver's wETH balance is increased by sent amount - assert_eq!(receiver_weth_after, receiver_weth_before + amount); } #[test] -/// Send bridged WNDs "back" from AssetHub Rococo to AssetHub Westend. -fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { +/// Send bridged assets "back" from AssetHub Rococo to AssetHub Westend. +/// +/// This mix of assets should cover the whole range: +/// - bridged native assets: ROC, +/// - bridged trust-based assets: USDT (exists only on Westend, Rococo gets it from Westend over +/// bridge), +/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from +/// Ethereum to Westend over Snowbridge, then bridged over to Rococo through this bridge). +fn send_back_wnds_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { let prefund_amount = 10_000_000_000_000u128; let amount_to_send = ASSET_HUB_WESTEND_ED * 1_000; let sender = AssetHubRococoSender::get(); @@ -269,9 +193,13 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { let prefund_accounts = vec![(sender.clone(), prefund_amount)]; create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), true, prefund_accounts); + //////////////////////////////////////////////////////////// + // Let's first send back just some WNDs as a simple example + //////////////////////////////////////////////////////////// + // 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)]); @@ -317,7 +245,7 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { }); let sender_wnds_after = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo, &sender); - let receiver_wnds_after = ::account_data_of(receiver).free; + let receiver_wnds_after = ::account_data_of(receiver.clone()).free; let wnds_in_reserve_on_ahw_after = ::account_data_of(sov_ahr_on_ahw).free; @@ -327,6 +255,96 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { assert!(receiver_wnds_after > receiver_wnds_before); // Reserve balance is reduced by sent amount assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before - amount_to_send); + + ////////////////////////////////////////////////////////////////// + // Now let's send back over USDTs + wETH (and pay fees with USDT) + ////////////////////////////////////////////////////////////////// + + // wETH has same relative location on both Westend and Rococo AssetHubs + let bridged_weth_at_ah = weth_at_asset_hubs(); + let bridged_usdt_at_asset_hub_rococo = bridged_usdt_at_ah_rococo(); + + // set up destination chain AH Westend: + // create a WND/USDT pool to be able to pay fees with USDT (USDT created in genesis) + set_up_pool_with_wnd_on_ah_westend(usdt_at_ah_westend(), false); + // create wETH on Westend (IRL it's already created by Snowbridge) + 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( + ByGenesis(ROCOCO_GENESIS_HASH), + AssetHubRococo::para_id(), + ); + AssetHubWestend::mint_asset( + ::RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + USDT_ID, + sov_ahr_on_ahw.clone(), + amount_to_send * 2, + ); + AssetHubWestend::mint_foreign_asset( + ::RuntimeOrigin::signed(AssetHubWestend::account_id_of(ALICE)), + bridged_weth_at_ah.clone(), + sov_ahr_on_ahw, + amount_to_send * 2, + ); + + // set up source chain AH Rococo: + // create wETH and USDT foreign assets on Rococo and prefund sender's account + let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)]; + create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true, prefund_accounts.clone()); + create_foreign_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true, prefund_accounts); + + // check balances before + let receiver_usdts_before = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(USDT_ID, &receiver) + }); + let receiver_weth_before = foreign_balance_on_ah_westend(bridged_weth_at_ah.clone(), &receiver); + + let usdt_id: AssetId = Location::try_from(bridged_usdt_at_asset_hub_rococo).unwrap().into(); + // send USDTs and wETHs + let assets: Assets = vec![ + (usdt_id.clone(), amount_to_send).into(), + (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount_to_send).into(), + ] + .into(); + // use USDT for fees + let fee = usdt_id; + + // use the more involved transfer extrinsic + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), + }]); + assert_ok!(AssetHubRococo::execute_with(|| { + ::PolkadotXcm::transfer_assets_using_type_and_then( + ::RuntimeOrigin::signed(sender.into()), + bx!(asset_hub_westend_location().into()), + bx!(assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify hops (also advances the message through the hops) + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + AssetHubWestend::execute_with(|| { + AssetHubWestend::assert_xcmp_queue_success(None); + }); + + let receiver_usdts_after = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(USDT_ID, &receiver) + }); + let receiver_weth_after = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); + + // Receiver's USDT balance is increased by almost `amount_to_send` (minus fees) + assert!(receiver_usdts_after > receiver_usdts_before); + assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send); + // Receiver's wETH balance is increased by `amount_to_send` + assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send); } #[test] @@ -339,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 = @@ -445,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)]); @@ -534,3 +552,12 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste assert!(receiver_wnds_after > receiver_wnds_before); assert!(receiver_wnds_after <= receiver_wnds_before + amount); } + +#[test] +fn dry_run_transfer_to_westend_sends_xcm_to_bridge_hub() { + test_dry_run_transfer_across_pk_bridge!( + AssetHubRococo, + BridgeHubRococo, + asset_hub_westend_location() + ); +} 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 a989881fef09..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,18 +14,32 @@ // limitations under the License. use crate::imports::*; +use xcm::opaque::v5; mod asset_transfers; mod claim_assets; +mod register_bridged_assets; mod send_xcm; 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 @@ -33,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 @@ -41,19 +55,19 @@ 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 -pub(crate) fn usdt_at_ah_rococo() -> Location { +pub(crate) fn usdt_at_ah_westend() -> Location { Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) } -pub(crate) fn bridged_usdt_at_ah_westend() -> Location { +pub(crate) fn bridged_usdt_at_ah_rococo() -> Location { Location::new( 2, [ - GlobalConsensus(Rococo), - Parachain(AssetHubRococo::para_id().into()), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into()), ], @@ -72,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)>, ) { @@ -81,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) @@ -100,23 +114,36 @@ 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(foreign_asset: v4::Location) { - 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(); let signed_owner = ::RuntimeOrigin::signed(owner.clone()); - assert_ok!(::ForeignAssets::mint( - signed_owner.clone(), - foreign_asset.clone().into(), - owner.clone().into(), - 3_000_000_000_000, - )); + 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(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + assert_ok!(::Assets::mint( + signed_owner.clone(), + asset_id.into(), + owner.clone().into(), + 3_000_000_000_000, + )); + } assert_ok!(::AssetConversion::create_pool( signed_owner.clone(), Box::new(wnd.clone()), - Box::new(foreign_asset.clone()), + Box::new(asset.clone()), )); assert_expected_events!( AssetHubWestend, @@ -127,7 +154,7 @@ pub(crate) fn set_up_pool_with_wnd_on_ah_westend(foreign_asset: v4::Location) { assert_ok!(::AssetConversion::add_liquidity( signed_owner.clone(), Box::new(wnd), - Box::new(foreign_asset), + Box::new(asset), 1_000_000_000_000, 2_000_000_000_000, 1, @@ -149,7 +176,7 @@ pub(crate) fn send_assets_from_asset_hub_rococo( fee_idx: u32, ) -> DispatchResult { let signed_origin = - ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + ::RuntimeOrigin::signed(AssetHubRococoSender::get()); let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); @@ -223,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( @@ -236,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 new file mode 100644 index 000000000000..1ae3a1b15805 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs @@ -0,0 +1,107 @@ +// 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::*, tests::*}; + +const XCM_FEE: u128 = 4_000_000_000_000; + +/// Tests the registering of a Rococo Asset as a bridged asset on Westend Asset Hub. +#[test] +fn register_rococo_asset_on_wah_from_rah() { + let sa_of_rah_on_wah = + AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + ByGenesis(ROCOCO_GENESIS_HASH), + AssetHubRococo::para_id(), + ); + + // Rococo Asset Hub asset when bridged to Westend Asset Hub. + let bridged_asset_at_wah = Location::new( + 2, + [ + GlobalConsensus(ByGenesis(ROCOCO_GENESIS_HASH)), + Parachain(AssetHubRococo::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(ASSET_ID.into()), + ], + ); + + // Encoded `create_asset` call to be executed in Westend Asset Hub ForeignAssets pallet. + let call = AssetHubWestend::create_foreign_asset_call( + bridged_asset_at_wah.clone(), + ASSET_MIN_BALANCE, + sa_of_rah_on_wah.clone(), + ); + + let origin_kind = OriginKind::Xcm; + let fee_amount = XCM_FEE; + let fees = (Parent, fee_amount).into(); + + let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_rah_on_wah.clone()); + + // SA-of-RAH-on-WAH needs to have balance to pay for fees and asset creation deposit + AssetHubWestend::fund_accounts(vec![( + sa_of_rah_on_wah.clone(), + ASSET_HUB_WESTEND_ED * 10000000000, + )]); + + let destination = asset_hub_westend_location(); + + // fund the RAH's SA on RBH for paying bridge transport fees + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); + + // set XCM versions + AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + + let root_origin = ::RuntimeOrigin::root(); + AssetHubRococo::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(destination.into()), + bx!(xcm), + )); + + AssetHubRococo::assert_xcm_pallet_sent(); + }); + + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + AssetHubWestend::assert_xcmp_queue_success(None); + assert_expected_events!( + AssetHubWestend, + vec![ + // Burned the fee + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == sa_of_rah_on_wah.clone(), + amount: *amount == fee_amount, + }, + // Foreign Asset created + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: asset_id == &bridged_asset_at_wah, + creator: *creator == sa_of_rah_on_wah.clone(), + owner: *owner == sa_of_rah_on_wah, + }, + // Unspent fee minted to origin + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sa_of_rah_on_wah.clone(), + }, + ] + ); + type ForeignAssets = ::ForeignAssets; + assert!(ForeignAssets::asset_exists(bridged_asset_at_wah)); + }); +} 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..931a3128f826 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 @@ -29,7 +29,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, }, @@ -60,15 +60,6 @@ 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(); @@ -82,6 +73,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..d59553574c26 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}; @@ -84,11 +84,7 @@ fn create_agent() { let remote_xcm = VersionedXcm::from(Xcm(vec![ 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(), - }, + Transact { origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into() }, ])); // Rococo Global Consensus @@ -142,11 +138,7 @@ fn create_channel() { let create_agent_xcm = VersionedXcm::from(Xcm(vec![ 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(), - }, + Transact { origin_kind: OriginKind::Xcm, call: create_agent_call.encode().into() }, ])); let create_channel_call = @@ -155,11 +147,7 @@ fn create_channel() { let create_channel_xcm = VersionedXcm::from(Xcm(vec![ 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(), - }, + Transact { origin_kind: OriginKind::Xcm, call: create_channel_call.encode().into() }, ])); // Rococo Global Consensus @@ -310,24 +298,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 +438,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 +554,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 44121cbfdafb..b87f25ac0f01 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 @@ -29,6 +29,7 @@ sp-runtime = { workspace = true } xcm = { workspace = true } pallet-xcm = { workspace = true } xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Bridges pallet-bridge-messages = { 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 d9b92cb11e92..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; @@ -32,21 +32,22 @@ mod imports { pub use emulated_integration_tests_common::{ accounts::ALICE, impls::Inspect, - test_parachain_is_trusted_teleporter, test_parachain_is_trusted_teleporter_for_relay, - test_relay_is_trusted_teleporter, + test_dry_run_transfer_across_pk_bridge, test_parachain_is_trusted_teleporter, + test_parachain_is_trusted_teleporter_for_relay, test_relay_is_trusted_teleporter, xcm_emulator::{ assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt, }, + xcm_helpers::xcm_transact_paid_execution, ASSETS_PALLET_ID, USDT_ID, }; pub use parachains_common::AccountId; pub use rococo_westend_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ - genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, - AssetHubRococoParaPallet as AssetHubRococoPallet, + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, }, asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, + AssetHubWestendParaPallet as AssetHubWestendPallet, }, bridge_hub_westend_emulated_chain::{ genesis::ED as BRIDGE_HUB_WESTEND_ED, BridgeHubWestendExistentialDeposit, @@ -55,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, @@ -70,10 +72,12 @@ 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; pub const ASSET_MIN_BALANCE: u128 = 1000; } 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 6492c520234f..ab09517339db 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,7 +12,9 @@ // 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 @@ -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()); @@ -113,19 +114,33 @@ fn send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah( } #[test] -/// Test transfer of WND from AssetHub Westend to AssetHub Rococo. -fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { +/// Test transfer of WND, USDT and wETH from AssetHub Westend to AssetHub Rococo. +/// +/// This mix of assets should cover the whole range: +/// - native assets: WND, +/// - trust-based assets: USDT (exists only on Westend, Rococo gets it from Westend over bridge), +/// - foreign asset / bridged asset (other bridge / Snowfork): wETH (bridged from Ethereum to +/// Westend over Snowbridge, then bridged over to Rococo through this bridge). +fn send_wnds_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { let amount = ASSET_HUB_WESTEND_ED * 1_000; let sender = AssetHubWestendSender::get(); let receiver = AssetHubRococoReceiver::get(); let wnd_at_asset_hub_westend = wnd_at_ah_westend(); 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_foreign_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 = @@ -161,7 +176,7 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { ); }); - let sender_wnds_after = ::account_data_of(sender).free; + let sender_wnds_after = ::account_data_of(sender.clone()).free; let receiver_wnds_after = foreign_balance_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, &receiver); let wnds_in_reserve_on_ahw_after = @@ -173,18 +188,88 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { assert!(receiver_wnds_after > receiver_wnds_before); // Reserve balance is increased by sent amount assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before + amount); + + ///////////////////////////////////////////////////////////// + // Now let's send over USDTs + wETH (and pay fees with USDT) + ///////////////////////////////////////////////////////////// + let usdt_at_asset_hub_westend = usdt_at_ah_westend(); + let bridged_usdt_at_asset_hub_rococo = bridged_usdt_at_ah_rococo(); + // wETH has same relative location on both Westend and Rococo AssetHubs + let bridged_weth_at_ah = weth_at_asset_hubs(); + + // mint USDT in sender's account (USDT already created in genesis) + AssetHubWestend::mint_asset( + ::RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + USDT_ID, + sender.clone(), + amount * 2, + ); + // create wETH at src and dest and prefund sender's account + create_foreign_on_ah_westend( + bridged_weth_at_ah.clone(), + true, + vec![(sender.clone(), amount * 2)], + ); + create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true); + create_foreign_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); + let receiver_weth_before = foreign_balance_on_ah_rococo(bridged_weth_at_ah.clone(), &receiver); + + // send USDTs and wETHs + let assets: Assets = vec![ + (usdt_at_asset_hub_westend.clone(), amount).into(), + (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount).into(), + ] + .into(); + // use USDT for fees + let fee: AssetId = usdt_at_asset_hub_westend.into(); + + // use the more involved transfer extrinsic + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), + }]); + assert_ok!(AssetHubWestend::execute_with(|| { + ::PolkadotXcm::transfer_assets_using_type_and_then( + ::RuntimeOrigin::signed(sender.into()), + bx!(asset_hub_rococo_location().into()), + bx!(assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify hops (also advances the message through the hops) + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + AssetHubRococo::execute_with(|| { + AssetHubRococo::assert_xcmp_queue_success(None); + }); + + let receiver_usdts_after = + foreign_balance_on_ah_rococo(bridged_usdt_at_asset_hub_rococo, &receiver); + let receiver_weth_after = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); + + // Receiver's USDT balance is increased by almost `amount` (minus fees) + assert!(receiver_usdts_after > receiver_usdts_before); + assert!(receiver_usdts_after < receiver_usdts_before + amount); + // Receiver's wETH balance is increased by sent amount + assert_eq!(receiver_weth_after, receiver_weth_before + amount); } #[test] -/// Send bridged assets "back" from AssetHub Rococo to AssetHub Westend. -/// -/// This mix of assets should cover the whole range: -/// - bridged native assets: ROC, -/// - bridged trust-based assets: USDT (exists only on Rococo, Westend gets it from Rococo over -/// bridge), -/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from -/// Ethereum to Rococo over Snowbridge, then bridged over to Westend through this bridge). -fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { +/// Send bridged ROCs "back" from AssetHub Westend to AssetHub Rococo. +fn send_back_rocs_from_asset_hub_westend_to_asset_hub_rococo() { let prefund_amount = 10_000_000_000_000u128; let amount_to_send = ASSET_HUB_ROCOCO_ED * 1_000; let sender = AssetHubWestendSender::get(); @@ -193,13 +278,9 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { let prefund_accounts = vec![(sender.clone(), prefund_amount)]; create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true, prefund_accounts); - //////////////////////////////////////////////////////////// - // Let's first send back just some ROCs as a simple example - //////////////////////////////////////////////////////////// - // 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)]); @@ -257,96 +338,6 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { assert!(receiver_rocs_after > receiver_rocs_before); // Reserve balance is reduced by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before - amount_to_send); - - ////////////////////////////////////////////////////////////////// - // Now let's send back over USDTs + wETH (and pay fees with USDT) - ////////////////////////////////////////////////////////////////// - - // wETH has same relative location on both Rococo and Westend AssetHubs - let bridged_weth_at_ah = weth_at_asset_hubs(); - let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend(); - - // set up destination chain AH Rococo: - // create a ROC/USDT pool to be able to pay fees with USDT (USDT created in genesis) - set_up_pool_with_roc_on_ah_rococo(usdt_at_ah_rococo(), false); - // create wETH on Rococo (IRL it's already created by Snowbridge) - create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true); - // prefund AHW's sovereign account on AHR to be able to withdraw USDT and wETH from reserves - let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, - AssetHubWestend::para_id(), - ); - AssetHubRococo::mint_asset( - ::RuntimeOrigin::signed(AssetHubRococoAssetOwner::get()), - USDT_ID, - sov_ahw_on_ahr.clone(), - amount_to_send * 2, - ); - AssetHubRococo::mint_foreign_asset( - ::RuntimeOrigin::signed(AssetHubRococo::account_id_of(ALICE)), - bridged_weth_at_ah.clone(), - sov_ahw_on_ahr, - amount_to_send * 2, - ); - - // set up source chain AH Westend: - // create wETH and USDT foreign assets on Westend and prefund sender's account - let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)]; - create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true, prefund_accounts.clone()); - create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend.clone(), true, prefund_accounts); - - // check balances before - let receiver_usdts_before = AssetHubRococo::execute_with(|| { - type Assets = ::Assets; - >::balance(USDT_ID, &receiver) - }); - let receiver_weth_before = foreign_balance_on_ah_rococo(bridged_weth_at_ah.clone(), &receiver); - - let usdt_id: AssetId = Location::try_from(bridged_usdt_at_asset_hub_westend).unwrap().into(); - // send USDTs and wETHs - let assets: Assets = vec![ - (usdt_id.clone(), amount_to_send).into(), - (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount_to_send).into(), - ] - .into(); - // use USDT for fees - let fee = usdt_id; - - // use the more involved transfer extrinsic - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), - }]); - assert_ok!(AssetHubWestend::execute_with(|| { - ::PolkadotXcm::transfer_assets_using_type_and_then( - ::RuntimeOrigin::signed(sender.into()), - bx!(asset_hub_rococo_location().into()), - bx!(assets.into()), - bx!(TransferType::DestinationReserve), - bx!(fee.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify hops (also advances the message through the hops) - assert_bridge_hub_westend_message_accepted(true); - assert_bridge_hub_rococo_message_received(); - AssetHubRococo::execute_with(|| { - AssetHubRococo::assert_xcmp_queue_success(None); - }); - - let receiver_usdts_after = AssetHubRococo::execute_with(|| { - type Assets = ::Assets; - >::balance(USDT_ID, &receiver) - }); - let receiver_weth_after = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); - - // Receiver's USDT balance is increased by almost `amount_to_send` (minus fees) - assert!(receiver_usdts_after > receiver_usdts_before); - assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send); - // Receiver's wETH balance is increased by `amount_to_send` - assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send); } #[test] @@ -359,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 = @@ -465,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)]); @@ -554,3 +545,304 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc assert!(receiver_rocs_after > receiver_rocs_before); assert!(receiver_rocs_after <= receiver_rocs_before + amount); } + +#[test] +fn dry_run_transfer_to_rococo_sends_xcm_to_bridge_hub() { + test_dry_run_transfer_across_pk_bridge!( + AssetHubWestend, + BridgeHubWestend, + 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 transport 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 f037a05a8276..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 @@ -17,17 +17,30 @@ use crate::imports::*; 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 @@ -35,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 @@ -43,19 +56,19 @@ 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 -pub(crate) fn usdt_at_ah_rococo() -> Location { +pub(crate) fn usdt_at_ah_westend() -> Location { Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) } -pub(crate) fn bridged_usdt_at_ah_westend() -> Location { +pub(crate) fn bridged_usdt_at_ah_rococo() -> Location { Location::new( 2, [ - GlobalConsensus(Rococo), - Parachain(AssetHubRococo::para_id().into()), + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into()), ], @@ -73,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)>, ) { @@ -88,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( @@ -238,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( @@ -251,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 new file mode 100644 index 000000000000..424f1e55956b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs @@ -0,0 +1,131 @@ +// 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::*, + tests::{ + snowbridge::{CHAIN_ID, WETH}, + *, + }, +}; + +const XCM_FEE: u128 = 40_000_000_000; + +/// Tests the registering of a Westend Asset as a bridged asset on Rococo Asset Hub. +#[test] +fn register_westend_asset_on_rah_from_wah() { + // Westend Asset Hub asset when bridged to Rococo Asset Hub. + let bridged_asset_at_rah = Location::new( + 2, + [ + GlobalConsensus(ByGenesis(WESTEND_GENESIS_HASH)), + Parachain(AssetHubWestend::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(ASSET_ID.into()), + ], + ); + // Register above asset on Rococo AH from Westend AH. + register_asset_on_rah_from_wah(bridged_asset_at_rah); +} + +/// Tests the registering of an Ethereum Asset as a bridged asset on Rococo Asset Hub. +#[test] +fn register_ethereum_asset_on_rah_from_wah() { + // Ethereum asset when bridged to Rococo Asset Hub. + let bridged_asset_at_rah = Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: WETH }, + ], + ); + // Register above asset on Rococo AH from Westend AH. + register_asset_on_rah_from_wah(bridged_asset_at_rah); +} + +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( + ByGenesis(WESTEND_GENESIS_HASH), + AssetHubWestend::para_id(), + ); + + // Encoded `create_asset` call to be executed in Rococo Asset Hub ForeignAssets pallet. + let call = AssetHubRococo::create_foreign_asset_call( + bridged_asset_at_rah.clone(), + ASSET_MIN_BALANCE, + sa_of_wah_on_rah.clone(), + ); + + let origin_kind = OriginKind::Xcm; + let fee_amount = XCM_FEE; + let fees = (Parent, fee_amount).into(); + + let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_wah_on_rah.clone()); + + // SA-of-WAH-on-RAH needs to have balance to pay for fees and asset creation deposit + AssetHubRococo::fund_accounts(vec![( + sa_of_wah_on_rah.clone(), + ASSET_HUB_ROCOCO_ED * 10000000000, + )]); + + let destination = asset_hub_rococo_location(); + + // fund the WAH's SA on WBH for paying bridge transport fees + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); + + // set XCM versions + AssetHubWestend::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + + let root_origin = ::RuntimeOrigin::root(); + AssetHubWestend::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(destination.into()), + bx!(xcm), + )); + + AssetHubWestend::assert_xcm_pallet_sent(); + }); + + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( + AssetHubRococo, + vec![ + // Burned the fee + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == sa_of_wah_on_rah.clone(), + amount: *amount == fee_amount, + }, + // Foreign Asset created + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: asset_id == &bridged_asset_at_rah, + creator: *creator == sa_of_wah_on_rah.clone(), + owner: *owner == sa_of_wah_on_rah, + }, + // Unspent fee minted to origin + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sa_of_wah_on_rah.clone(), + }, + ] + ); + type ForeignAssets = ::ForeignAssets; + assert!(ForeignAssets::asset_exists(bridged_asset_at_rah)); + }); +} 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..787d7dc842cb 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 @@ -29,7 +29,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, }, @@ -60,15 +60,6 @@ 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(); @@ -82,6 +73,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..db42704dae61 --- /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 }, + 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 transport 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/src/tests/fellowship.rs b/cumulus/parachains/integration-tests/emulated/tests/collectives/collectives-westend/src/tests/fellowship.rs index f97599bda7f0..80b82e0c446f 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,7 +36,6 @@ 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 } ) 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..8418e3da3bba 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 @@ -64,11 +64,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 +102,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 +180,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/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 584bce8f1df7..9915b1753ef6 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 @@ -46,7 +46,7 @@ fn transact_hardcoded_weights_are_sane() { // Create and populate schedule with the worst case assignment on this core. let mut schedule = Vec::new(); - for i in 0..27 { + for i in 0..80 { schedule.push(ScheduleItem { mask: CoreMask::void().set(i), assignment: CoreAssignment::Task(2000 + i), 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 f61bc4285a0c..00530f80b958 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 @@ -46,7 +46,7 @@ fn transact_hardcoded_weights_are_sane() { // Create and populate schedule with the worst case assignment on this core. let mut schedule = Vec::new(); - for i in 0..27 { + for i in 0..80 { schedule.push(ScheduleItem { mask: CoreMask::void().set(i), assignment: CoreAssignment::Task(2000 + i), 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/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/pallets/ping/src/lib.rs b/cumulus/parachains/pallets/ping/src/lib.rs index 729494cbd251..2cf32c891fc0 100644 --- a/cumulus/parachains/pallets/ping/src/lib.rs +++ b/cumulus/parachains/pallets/ping/src/lib.rs @@ -108,7 +108,6 @@ 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(), @@ -209,7 +208,6 @@ 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(), diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 47e0983a4150..42adaba7a27c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -49,6 +49,7 @@ 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-offchain = { workspace = true } @@ -116,6 +117,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-asset-conversion-ops/runtime-benchmarks", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets-freezer/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -127,6 +129,7 @@ runtime-benchmarks = [ "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", @@ -239,6 +242,7 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", 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 1dbd92d6bff0..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 @@ -18,10 +18,12 @@ 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::{genesis_config_helpers::*, AccountId, AuraId}; -use sp_core::{crypto::UncheckedInto, sr25519}; +use parachains_common::{AccountId, AuraId}; +use sp_core::crypto::UncheckedInto; use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; use testnet_parachains_constants::rococo::{currency::UNITS as ROC, xcm_version::SAFE_XCM_VERSION}; const ASSET_HUB_ROCOCO_ED: Balance = ExistentialDeposit::get(); @@ -32,15 +34,14 @@ fn asset_hub_rococo_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_ROCOCO_ED * 16, - ..Default::default() }, session: SessionConfig { keys: invulnerables @@ -53,16 +54,9 @@ fn asset_hub_rococo_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. @@ -73,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 @@ -106,46 +100,24 @@ 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![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], - ROC * 1_000_000, + Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect(), + 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![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], ROC * 1_000_000, 1000.into(), 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 367cf8a51f2c..2f9d83bd9d0b 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, @@ -82,7 +82,7 @@ use parachains_common::{ use sp_runtime::{Perbill, RuntimeDebug}; use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use xcm_config::{ - ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, + ForeignAssetsConvertedConcreteId, GovernanceLocation, LocationToAccountId, PoolAssetsConvertedConcreteId, TokenLocation, TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocation, }; @@ -103,7 +103,7 @@ use xcm::latest::prelude::{ }; use xcm::{ latest::prelude::{AssetId, BodyId}, - VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, + VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, }; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -120,10 +120,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_001, + spec_version: 1_016_002, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -175,6 +175,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -229,6 +230,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -328,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, >; @@ -340,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< @@ -379,7 +381,7 @@ impl pallet_asset_conversion::Config for Runtime { TokenLocation, parachain_info::Pallet, xcm_config::TrustBackedAssetsPalletIndex, - xcm::v4::Location, + xcm::v5::Location, >; } @@ -413,17 +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_westend::WestendOrEthereumAssetFromAssetHubWestend, ), - ForeignCreatorsSovereignAccountOf, + LocationToAccountId, AccountId, - xcm::v4::Location, + xcm::v5::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -810,13 +813,16 @@ 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, AssetConversion, ResolveAssetTo, >; + type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -997,8 +1003,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1012,7 +1018,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( InitStorageVersions, @@ -1097,14 +1103,81 @@ pub type Executive = frame_executive::Executive< Migrations, >; +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< + AccountId, + cumulus_primitives_core::Location, + cumulus_primitives_core::Location, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (Location, Location) { + // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. + let asset_id = Location::new( + 1, + [ + cumulus_primitives_core::Junction::Parachain(3000), + cumulus_primitives_core::Junction::PalletInstance(53), + cumulus_primitives_core::Junction::GeneralIndex(seed.into()), + ], + ); + (asset_id.clone(), asset_id) + } + + fn setup_balances_and_pool(asset_id: cumulus_primitives_core::Location, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(ForeignAssets::force_create( + RuntimeOrigin::root(), + asset_id.clone().into(), + account.clone().into(), /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = account.clone(); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&lp_provider, u64::MAX.into()); + assert_ok!(ForeignAssets::mint_into( + asset_id.clone().into(), + &lp_provider, + u64::MAX.into() + )); + + let token_native = alloc::boxed::Box::new(TokenLocation::get()); + let token_second = alloc::boxed::Box::new(asset_id); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider.clone()), + token_native.clone(), + token_second.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider.clone()), + token_native, + token_second, + (u32::MAX / 8).into(), // 1 desired + u32::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider, + )); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetTxPayment] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -1115,6 +1188,7 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1234,16 +1308,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() } } @@ -1334,19 +1408,45 @@ impl_runtime_apis! { impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { - let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; + let native_token = xcm_config::TokenLocation::get(); + // 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::v5::Location + >(&native_token).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?.into_iter(); + acceptable_assets.extend(assets_in_pool_with_native); 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::() { - Ok(asset_id) if asset_id.0 == xcm_config::TokenLocation::get() => { + Ok(asset_id) if asset_id.0 == native_asset => { // for native token - Ok(WeightToFee::weight_to_fee(&weight)) + Ok(fee_in_native) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); - Err(XcmPaymentApiError::AssetNotFound) + let assets_in_pool_with_this_asset: Vec<_> = assets_common::get_assets_in_pool_with::< + Runtime, + xcm::v5::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, + native_asset, + fee_in_native, + true, // We include the fee. + ).ok_or(XcmPaymentApiError::AssetNotFound) + } else { + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + } }, Err(_) => { log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); @@ -1426,6 +1526,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; @@ -1455,11 +1556,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1732,7 +1834,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 }]), + )) } } @@ -1781,6 +1888,15 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..182410f20fff --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --chain=asset-hub-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index f20790cde39c..33f111009ed0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -19,8 +19,10 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_asset_conversion; pub mod pallet_asset_conversion_ops; +pub mod pallet_asset_conversion_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -33,6 +35,7 @@ pub mod pallet_nfts; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs new file mode 100644 index 000000000000..0a639b368af2 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs @@ -0,0 +1,92 @@ +// 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 . + +//! Autogenerated weights for `pallet_asset_conversion_tx_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-04, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Georges-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_asset_conversion_tx_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --chain=asset-hub-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_conversion_tx_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_tx_payment::WeightInfo for WeightInfo { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 209_000_000 picoseconds. + Weight::from_parts(212_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `631` + // Estimated: `7404` + // Minimum execution time: 1_228_000_000 picoseconds. + Weight::from_parts(1_268_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..035f9a6dbe51 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --chain=asset-hub-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/mod.rs index 8c52ecd9f1b1..025c39bcee07 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -81,11 +84,7 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -132,12 +131,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 +172,9 @@ impl XcmWeightInfo for AssetHubRococoXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -223,10 +248,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..b69c136b29d9 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 set_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 fab0141e6d41..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, >, ), @@ -361,8 +364,8 @@ impl xcm_executor::Config for XcmConfig { // to the Westend ecosystem. We also allow Ethereum contracts to act as reserves for the foreign // assets identified by the same respective contracts locations. type IsReserve = ( - bridging::to_westend::WestendAssetFromAssetHubWestend, - bridging::to_ethereum::IsTrustedBridgedReserveLocationForForeignAsset, + bridging::to_westend::WestendOrEthereumAssetFromAssetHubWestend, + bridging::to_ethereum::EthereumAssetFromEthereum, ); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; @@ -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 = (); @@ -512,19 +516,12 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } -pub type ForeignCreatorsSovereignAccountOf = ( - SiblingParachainConvertsVia, - AccountId32Aliases, - ParentIsPreset, - GlobalConsensusEthereumConvertsFor, -); - /// 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)]) } } @@ -588,8 +585,10 @@ 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())]); pub WndLocation: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]); pub AssetHubWestend: Location = Location::new(2, [ GlobalConsensus(WestendNetwork::get()), @@ -627,9 +626,12 @@ pub mod bridging { } } - /// Allow any asset native to the Westend ecosystem if it comes from Westend Asset Hub. - pub type WestendAssetFromAssetHubWestend = - matching::RemoteAssetFromLocation, AssetHubWestend>; + /// Allow any asset native to the Westend or Ethereum ecosystems if it comes from Westend + /// Asset Hub. + pub type WestendOrEthereumAssetFromAssetHubWestend = matching::RemoteAssetFromLocation< + (StartsWith, StartsWith), + AssetHubWestend, + >; } pub mod to_ethereum { @@ -654,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(( @@ -667,12 +669,12 @@ 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())), ] ); } - pub type IsTrustedBridgedReserveLocationForForeignAsset = + pub type EthereumAssetFromEthereum = IsForeignConcreteAsset>; impl Contains<(Location, Junction)> for UniversalAliases { 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 6e10f9168990..5da8b45417a3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -21,8 +21,8 @@ use asset_hub_rococo_runtime::{ xcm_config, xcm_config::{ bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, - LocationToAccountId, StakingPot, TokenLocation, TrustBackedAssetsPalletLocation, XcmConfig, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, + TokenLocation, TrustBackedAssetsPalletLocation, XcmConfig, }, AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, @@ -941,7 +941,7 @@ asset_test_utils::include_teleports_for_foreign_assets_works!( CheckingAccount, WeightToFee, ParachainSystem, - ForeignCreatorsSovereignAccountOf, + LocationToAccountId, ForeignAssetsInstance, collator_session_keys(), slot_durations(), @@ -1015,7 +1015,7 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p Runtime, XcmConfig, WeightToFee, - ForeignCreatorsSovereignAccountOf, + LocationToAccountId, ForeignAssetsInstance, Location, WithLatestLocationConverter, @@ -1078,6 +1078,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 +1109,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 +1146,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 +1185,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 +1215,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() ), || { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 1434c3e3b601..d5eaa43ab834 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -44,11 +44,13 @@ 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-offchain = { workspace = true } @@ -117,6 +119,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-asset-conversion-ops/runtime-benchmarks", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets-freezer/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -127,8 +130,10 @@ runtime-benchmarks = [ "pallet-nft-fractionalization/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", + "pallet-revive/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", @@ -166,6 +171,7 @@ try-runtime = [ "pallet-nft-fractionalization/try-runtime", "pallet-nfts/try-runtime", "pallet-proxy/try-runtime", + "pallet-revive/try-runtime", "pallet-session/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-timestamp/try-runtime", @@ -218,6 +224,7 @@ std = [ "pallet-nfts-runtime-api/std", "pallet-nfts/std", "pallet-proxy/std", + "pallet-revive/std", "pallet-session/std", "pallet-state-trie-migration/std", "pallet-timestamp/std", @@ -242,6 +249,7 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", 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 b287dcd56219..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,10 +18,12 @@ 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::{genesis_config_helpers::*, AccountId, AuraId}; -use sp_core::{crypto::UncheckedInto, sr25519}; +use parachains_common::{AccountId, AuraId}; +use sp_core::crypto::UncheckedInto; use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; use testnet_parachains_constants::westend::{ currency::UNITS as WND, xcm_version::SAFE_XCM_VERSION, }; @@ -34,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 @@ -55,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. @@ -75,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![ ( @@ -104,46 +98,24 @@ 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![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 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![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], WND * 1_000_000, 1000.into(), 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 bb77f576e20d..2206aea78ec2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -47,7 +47,7 @@ use frame_support::{ fungible, fungibles, tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, InstanceFilter, - TransformOrigin, + Nothing, TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -58,15 +58,16 @@ use frame_system::{ }; use pallet_asset_conversion_tx_payment::SwapAssetAdapter; use pallet_nfts::{DestroyWitness, PalletFeatures}; +use pallet_revive::{evm::runtime::EthExtra, AddressMapper}; 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}; +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, @@ -78,9 +79,9 @@ use testnet_parachains_constants::westend::{ consensus::*, currency::*, fee::WeightToFee, snowbridge::EthereumNetwork, time::*, }; use xcm_config::{ - ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, - PoolAssetsConvertedConcreteId, TrustBackedAssetsConvertedConcreteId, - TrustBackedAssetsPalletLocation, WestendLocation, XcmOriginToTransactDispatchOrigin, + ForeignAssetsConvertedConcreteId, LocationToAccountId, PoolAssetsConvertedConcreteId, + TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocation, WestendLocation, + XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -93,7 +94,7 @@ use assets_common::{ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::{ latest::prelude::AssetId, - prelude::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}, + prelude::{VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}, }; #[cfg(feature = "runtime-benchmarks")] @@ -120,10 +121,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_001, + spec_version: 1_016_006, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, @@ -175,6 +176,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -229,6 +231,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -326,11 +329,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, >; @@ -338,21 +341,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< @@ -377,7 +380,7 @@ impl pallet_asset_conversion::Config for Runtime { WestendLocation, parachain_info::Pallet, xcm_config::TrustBackedAssetsPalletIndex, - xcm::v4::Location, + xcm::v5::Location, >; } @@ -411,17 +414,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, ), - ForeignCreatorsSovereignAccountOf, + LocationToAccountId, AccountId, - xcm::v4::Location, + xcm::v5::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -803,13 +807,16 @@ 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, AssetConversion, ResolveAssetTo, >; + type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -928,6 +935,53 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; } +parameter_types! { + pub const DepositPerItem: Balance = deposit(1, 0); + pub const DepositPerByte: Balance = deposit(0, 1); + pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(30); +} + +type EventRecord = frame_system::EventRecord< + ::RuntimeEvent, + ::Hash, +>; + +impl pallet_revive::Config for Runtime { + type Time = Timestamp; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type WeightPrice = pallet_transaction_payment::Pallet; + type WeightInfo = pallet_revive::weights::SubstrateWeight; + type ChainExtension = (); + type AddressMapper = pallet_revive::AccountId32Mapper; + type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; + type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; + type UnsafeUnstableInterface = ConstBool; + type UploadOrigin = EnsureSigned; + type InstantiateOrigin = EnsureSigned; + type RuntimeHoldReason = RuntimeHoldReason; + type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; + type Debug = (); + type Xcm = pallet_xcm::Pallet; + type ChainId = ConstU64<420_420_421>; + type NativeToEthRatio = ConstU32<1_000_000>; // 10^(18 - 12) Eth is 10^18, Native is 10^12. +} + +impl TryFrom for pallet_revive::Call { + type Error = (); + + fn try_from(value: RuntimeCall) -> Result { + match value { + RuntimeCall::Revive(call) => Ok(call), + _ => Err(()), + } + } +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -976,6 +1030,7 @@ construct_runtime!( AssetsFreezer: pallet_assets_freezer:: = 57, ForeignAssetsFreezer: pallet_assets_freezer:: = 58, PoolAssetsFreezer: pallet_assets_freezer:: = 59, + Revive: pallet_revive = 60, StateTrieMigration: pallet_state_trie_migration = 70, @@ -993,8 +1048,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1006,9 +1061,34 @@ pub type SignedExtra = ( cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, frame_metadata_hash_extension::CheckMetadataHash, ); + +/// Default extensions applied to Ethereum transactions. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct EthExtraImpl; + +impl EthExtra for EthExtraImpl { + type Config = Runtime; + type Extension = TxExtension; + + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckMortality::from(generic::Era::Immortal), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from(tip, None), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), + ) + } +} + /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + pallet_revive::evm::runtime::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -1147,14 +1227,86 @@ pub type Executive = frame_executive::Executive< Migrations, >; +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< + AccountId, + cumulus_primitives_core::Location, + cumulus_primitives_core::Location, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter( + seed: u32, + ) -> (cumulus_primitives_core::Location, cumulus_primitives_core::Location) { + // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. + let asset_id = cumulus_primitives_core::Location::new( + 1, + [ + cumulus_primitives_core::Junction::Parachain(3000), + cumulus_primitives_core::Junction::PalletInstance(53), + cumulus_primitives_core::Junction::GeneralIndex(seed.into()), + ], + ); + (asset_id.clone(), asset_id) + } + + fn setup_balances_and_pool(asset_id: cumulus_primitives_core::Location, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(ForeignAssets::force_create( + RuntimeOrigin::root(), + asset_id.clone().into(), + account.clone().into(), /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = account.clone(); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&lp_provider, u64::MAX.into()); + assert_ok!(ForeignAssets::mint_into( + asset_id.clone().into(), + &lp_provider, + u64::MAX.into() + )); + + let token_native = alloc::boxed::Box::new(cumulus_primitives_core::Location::new( + 1, + cumulus_primitives_core::Junctions::Here, + )); + let token_second = alloc::boxed::Box::new(asset_id); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider.clone()), + token_native.clone(), + token_second.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider.clone()), + token_native, + token_second, + (u32::MAX / 2).into(), // 1 desired + u32::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider, + )); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetTxPayment] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -1165,11 +1317,13 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] [pallet_asset_conversion_ops, AssetConversionMigration] + [pallet_revive, Revive] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. @@ -1328,18 +1482,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() } } @@ -1367,19 +1521,46 @@ impl_runtime_apis! { impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { - let acceptable_assets = vec![AssetId(xcm_config::WestendLocation::get())]; + let native_token = xcm_config::WestendLocation::get(); + // 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::v5::Location + >(&native_token).map_err(|()| XcmPaymentApiError::VersionedConversionFailed)?.into_iter(); + acceptable_assets.extend(assets_in_pool_with_native); 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::() { - Ok(asset_id) if asset_id.0 == xcm_config::WestendLocation::get() => { - // for native token - Ok(WeightToFee::weight_to_fee(&weight)) + Ok(asset_id) if asset_id.0 == native_asset => { + // for native asset + Ok(fee_in_native) }, Ok(asset_id) => { - log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); - Err(XcmPaymentApiError::AssetNotFound) + // 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::v5::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, + native_asset, + fee_in_native, + true, // We include the fee. + ).ok_or(XcmPaymentApiError::AssetNotFound) + } else { + log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - unhandled asset_id: {asset_id:?}!"); + Err(XcmPaymentApiError::AssetNotFound) + } }, Err(_) => { log::trace!(target: "xcm::xcm_runtime_apis", "query_weight_to_asset_fee - failed to convert asset: {asset:?}!"); @@ -1522,6 +1703,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; @@ -1551,11 +1733,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1814,7 +1997,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), }) } @@ -1828,7 +2011,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 }]), + )) } } @@ -1877,6 +2065,126 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + + impl pallet_revive::ReviveApi for Runtime + { + 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: U256, + input: Vec, + gas_limit: Option, + storage_deposit_limit: Option, + ) -> pallet_revive::EthContractResult + { + use pallet_revive::AddressMapper; + let blockweights = ::BlockWeights::get(); + let origin = ::AddressMapper::to_account_id(&from); + + let encoded_size = |pallet_call| { + let call = RuntimeCall::Revive(pallet_call); + let uxt: UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into(); + uxt.encoded_size() as u32 + }; + + Revive::bare_eth_transact( + origin, + dest, + value, + input, + gas_limit.unwrap_or(blockweights.max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + encoded_size, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + + fn call( + origin: AccountId, + dest: H160, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + input_data: Vec, + ) -> pallet_revive::ContractResult { + let blockweights= ::BlockWeights::get(); + Revive::bare_call( + RuntimeOrigin::signed(origin), + dest, + value, + gas_limit.unwrap_or(blockweights.max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + input_data, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + + fn instantiate( + origin: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + code: pallet_revive::Code, + data: Vec, + salt: Option<[u8; 32]>, + ) -> pallet_revive::ContractResult + { + let blockweights= ::BlockWeights::get(); + Revive::bare_instantiate( + RuntimeOrigin::signed(origin), + value, + gas_limit.unwrap_or(blockweights.max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + code, + data, + salt, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + ) -> pallet_revive::CodeUploadResult + { + Revive::bare_upload_code( + RuntimeOrigin::signed(origin), + code, + storage_deposit_limit.unwrap_or(u128::MAX), + ) + } + + fn get_storage( + address: H160, + key: [u8; 32], + ) -> pallet_revive::GetStorageResult { + Revive::get_storage( + address, + key + ) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..e8dd9763c282 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --chain=asset-hub-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_206_000 picoseconds. + Weight::from_parts(6_212_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_851_000 picoseconds. + Weight::from_parts(8_847_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_851_000 picoseconds. + Weight::from_parts(8_847_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 631_000 picoseconds. + Weight::from_parts(3_086_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_446_000 picoseconds. + Weight::from_parts(5_911_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 481_000 picoseconds. + Weight::from_parts(2_916_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_927_000 picoseconds. + Weight::from_parts(6_613_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 4eebb1f8d786..b0f986768f40 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -18,8 +18,10 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_asset_conversion; pub mod pallet_asset_conversion_ops; +pub mod pallet_asset_conversion_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -32,6 +34,7 @@ pub mod pallet_nfts; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs new file mode 100644 index 000000000000..8fe302630fb9 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs @@ -0,0 +1,92 @@ +// 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 . + +//! Autogenerated weights for `pallet_asset_conversion_tx_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-04, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Georges-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_asset_conversion_tx_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --chain=asset-hub-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_conversion_tx_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_tx_payment::WeightInfo for WeightInfo { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 214_000_000 picoseconds. + Weight::from_parts(219_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `631` + // Estimated: `7404` + // Minimum execution time: 1_211_000_000 picoseconds. + Weight::from_parts(1_243_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..b4c78a78b489 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --chain=asset-hub-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 40_847_000 picoseconds. + Weight::from_parts(49_674_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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/xcm/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/mod.rs index d39052c5c03b..35ff2dc367c0 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -80,11 +83,7 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -132,12 +131,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 +172,9 @@ impl XcmWeightInfo for AssetHubWestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -223,10 +248,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..528694123115 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 set_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 614ef81a4fa1..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, >, ), @@ -383,8 +386,8 @@ impl xcm_executor::Config for XcmConfig { // held). On Westend Asset Hub, we allow Rococo Asset Hub to act as reserve for any asset native // to the Rococo or Ethereum ecosystems. type IsReserve = ( - bridging::to_rococo::RococoOrEthereumAssetFromAssetHubRococo, - bridging::to_ethereum::IsTrustedBridgedReserveLocationForForeignAsset, + bridging::to_rococo::RococoAssetFromAssetHubRococo, + bridging::to_ethereum::EthereumAssetFromEthereum, ); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; @@ -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 = (); @@ -535,19 +539,12 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } -pub type ForeignCreatorsSovereignAccountOf = ( - SiblingParachainConvertsVia, - AccountId32Aliases, - ParentIsPreset, - GlobalConsensusEthereumConvertsFor, -); - /// 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)]) } } @@ -603,11 +600,9 @@ pub mod bridging { ] ); - pub const RococoNetwork: NetworkId = NetworkId::Rococo; - pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; + 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 EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); pub AssetHubRococo: Location = Location::new(2, [ GlobalConsensus(RococoNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID) @@ -644,12 +639,9 @@ pub mod bridging { } } - /// Allow any asset native to the Rococo or Ethereum ecosystems if it comes from Rococo - /// Asset Hub. - pub type RococoOrEthereumAssetFromAssetHubRococo = matching::RemoteAssetFromLocation< - (StartsWith, StartsWith), - AssetHubRococo, - >; + /// Allow any asset native to the Rococo ecosystem if it comes from Rococo Asset Hub. + pub type RococoAssetFromAssetHubRococo = + matching::RemoteAssetFromLocation, AssetHubRococo>; } pub mod to_ethereum { @@ -679,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(( @@ -692,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())), ] ); @@ -703,7 +695,7 @@ pub mod bridging { pub type EthereumNetworkExportTable = xcm_builder::NetworkExportTable; - pub type IsTrustedBridgedReserveLocationForForeignAsset = + pub type EthereumAssetFromEthereum = IsForeignConcreteAsset>; impl Contains<(Location, Junction)> for UniversalAliases { 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 ff84bdea69f4..5d0f843554a1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -21,9 +21,8 @@ use asset_hub_westend_runtime::{ xcm_config, xcm_config::{ bridging, AssetFeeAsExistentialDepositMultiplierFeeCharger, CheckingAccount, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, ForeignCreatorsSovereignAccountOf, - LocationToAccountId, StakingPot, TrustBackedAssetsPalletLocation, WestendLocation, - XcmConfig, + ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, LocationToAccountId, StakingPot, + TrustBackedAssetsPalletLocation, WestendLocation, XcmConfig, }, AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, @@ -53,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; @@ -88,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, ), ) { @@ -96,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); @@ -221,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") ) )); @@ -232,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, @@ -273,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 = @@ -312,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(), }; @@ -499,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(), }; @@ -523,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)); @@ -538,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 }; @@ -547,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 @@ -835,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(), }; @@ -930,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(), @@ -966,7 +968,7 @@ asset_test_utils::include_teleports_for_foreign_assets_works!( CheckingAccount, WeightToFee, ParachainSystem, - ForeignCreatorsSovereignAccountOf, + LocationToAccountId, ForeignAssetsInstance, collator_session_keys(), slot_durations(), @@ -1023,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(|| { @@ -1044,10 +1046,10 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p Runtime, XcmConfig, WeightToFee, - ForeignCreatorsSovereignAccountOf, + LocationToAccountId, ForeignAssetsInstance, - xcm::v4::Location, - WithLatestLocationConverter, + xcm::v5::Location, + WithLatestLocationConverter, collator_session_keys(), ExistentialDeposit::get(), AssetDeposit::get(), @@ -1124,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(); @@ -1155,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() ), || { @@ -1193,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(); @@ -1217,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() ), || { diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index deda5fa4ab9c..1d2d45b42c5d 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -26,6 +26,9 @@ pub mod runtime_api; extern crate alloc; use crate::matching::{LocalLocationPattern, ParentLocation}; +use alloc::vec::Vec; +use codec::{Decode, EncodeLike}; +use core::cmp::PartialEq; use frame_support::traits::{Equals, EverythingBut}; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId}; use sp_runtime::traits::TryConvertInto; @@ -134,6 +137,36 @@ 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)| { + if asset_1 == *asset { + Some(asset_2) + } else if asset_2 == *asset { + Some(asset_1) + } else { + None + } + }) + .map(|location| location.try_into().map_err(|_| ()).map(AssetId)) + .collect::, _>>() +} + #[cfg(test)] mod tests { use super::*; @@ -260,15 +293,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![ @@ -315,18 +348,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, )), @@ -334,9 +367,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, )), @@ -344,9 +377,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], ))], ), @@ -364,14 +397,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, @@ -381,7 +414,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 9bb35d0c5328..aa9d7929cb93 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -102,19 +102,27 @@ impl< pub struct RemoteAssetFromLocation( core::marker::PhantomData<(AssetsAllowedNetworks, OriginLocation)>, ); -impl, OriginLocation: Get> - ContainsPair for RemoteAssetFromLocation +impl< + L: TryInto + Clone, + AssetsAllowedNetworks: Contains, + OriginLocation: Get, + > ContainsPair for RemoteAssetFromLocation { - fn contains(asset: &Asset, origin: &Location) -> bool { + fn contains(asset: &L, origin: &L) -> bool { + let Ok(asset) = asset.clone().try_into() else { + return false; + }; + let Ok(origin) = origin.clone().try_into() else { + return false; + }; let expected_origin = OriginLocation::get(); // ensure `origin` is expected `OriginLocation` - if !expected_origin.eq(origin) { + if !expected_origin.eq(&origin) { log::trace!( target: "xcm::contains", - "RemoteAssetFromLocation asset: {:?}, origin: {:?} is not from expected {:?}", - asset, origin, expected_origin, + "RemoteAssetFromLocation asset: {asset:?}, origin: {origin:?} is not from expected {expected_origin:?}" ); - return false + return false; } else { log::trace!( target: "xcm::contains", @@ -123,7 +131,14 @@ impl, OriginLocation: Get> } // ensure `asset` is from remote consensus listed in `AssetsAllowedNetworks` - AssetsAllowedNetworks::contains(&asset.id.0) + AssetsAllowedNetworks::contains(&asset) + } +} +impl, OriginLocation: Get> + ContainsPair for RemoteAssetFromLocation +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + >::contains(&asset.id.0, origin) } } @@ -131,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] @@ -143,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 @@ -180,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/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs index c80222142304..8dc720e27753 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -367,9 +367,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 +381,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(), }; @@ -1202,19 +1202,13 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor 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: Weight::from_parts(40_000_000_000, 8000), - call: foreign_asset_create.into(), - }, + Transact { origin_kind: OriginKind::Xcm, call: foreign_asset_create.into() }, Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_set_metadata.into(), }, Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_set_team.into(), }, ExpectTransactStatus(MaybeErrorCode::Success), @@ -1321,11 +1315,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor 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: Weight::from_parts(20_000_000_000, 8000), - call: foreign_asset_create.into(), - }, + Transact { origin_kind: OriginKind::Xcm, call: foreign_asset_create.into() }, ExpectTransactStatus(MaybeErrorCode::from(DispatchError::BadOrigin.encode())), ]); 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..4f144e24aa30 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> 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 9a76e61ecb20..4af8a9f43850 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -13,14 +13,10 @@ workspace = true substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { features = [ - "derive", -], workspace = true } +codec = { features = ["derive"], workspace = true } hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { features = [ - "derive", -], workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } serde_json = { features = ["alloc"], workspace = true } @@ -47,6 +43,7 @@ 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 } @@ -74,9 +71,7 @@ cumulus-pallet-aura-ext = { 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-pallet-xcmp-queue = { features = ["bridging"], workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } @@ -126,7 +121,6 @@ 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 } -sp-keyring = { workspace = true, default-features = true } snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] @@ -210,6 +204,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -246,6 +241,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm-bridge-hub/runtime-benchmarks", 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 c971fa59c68d..7e0385692375 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 @@ -38,7 +38,7 @@ use frame_support::{ use frame_system::{EnsureNever, EnsureRoot}; use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ - BridgeRelayersSignedExtension, WithMessagesExtensionConfig, + BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; use pallet_xcm_bridge_hub::XcmAsPlainPayload; use polkadot_parachain_primitives::primitives::Sibling; @@ -92,9 +92,9 @@ type FromRococoBulletinMessageBlobDispatcher = BridgeBlobDispatcher< BridgeRococoToRococoBulletinMessagesPalletInstance, >; -/// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin -/// chain. -pub type OnBridgeHubRococoRefundRococoBulletinMessages = BridgeRelayersSignedExtension< +/// Transaction extension that refunds relayers that are delivering messages from the Rococo +/// Bulletin chain. +pub type OnBridgeHubRococoRefundRococoBulletinMessages = BridgeRelayersTransactionExtension< Runtime, WithMessagesExtensionConfig< StrOnBridgeHubRococoRefundRococoBulletinMessages, @@ -246,12 +246,13 @@ 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(); let bridge_id = BridgeId::new(&universal_source, &universal_destination); 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 8fe045723107..0eab3c74a7e2 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 @@ -37,20 +37,20 @@ use frame_support::{parameter_types, traits::PalletInfoAccess}; use frame_system::{EnsureNever, EnsureRoot}; use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ - BridgeRelayersSignedExtension, WithMessagesExtensionConfig, + BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; 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())] @@ -84,8 +84,9 @@ pub type ToWestendBridgeHubMessagesDeliveryProof = type FromWestendMessageBlobDispatcher = BridgeBlobDispatcher; -/// Signed extension that refunds relayers that are delivering messages from the Westend parachain. -pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersSignedExtension< +/// Transaction extension that refunds relayers that are delivering messages from the Westend +/// parachain. +pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersTransactionExtension< Runtime, WithMessagesExtensionConfig< StrOnBridgeHubRococoRefundBridgeHubWestendMessages, @@ -174,13 +175,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 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 07048d54ab1b..98e2450ee832 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 parachains_common::{genesis_config_helpers::*, AccountId, AuraId}; -use sp_core::sr25519; +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,101 +59,45 @@ fn bridge_hub_rococo_genesis( ) }) .collect(), - ..Default::default() - }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - }, - bridge_westend_grandpa: BridgeWestendGrandpaConfig { - owner: bridges_pallet_owner.clone(), - ..Default::default() }, + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, + 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() - }, - ..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![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1013.into(), - Some(get_account_id_from_seed::("Bob")), + Some(Sr25519Keyring::Bob.to_account_id()), rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(), vec![( 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])), )], ), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => bridge_hub_rococo_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => bridge_hub_rococo_genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1013.into(), - Some(get_account_id_from_seed::("Bob")), + Some(Sr25519Keyring::Bob.to_account_id()), rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(), vec![], ), 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 e3435f35f178..ff7af475f5e2 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}; @@ -120,8 +123,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -132,13 +135,13 @@ pub type SignedExtra = ( pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages,), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, frame_metadata_hash_extension::CheckMetadataHash, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -235,8 +238,8 @@ 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, impl_version: 0, @@ -298,6 +301,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -358,6 +363,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -650,12 +656,14 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1037,6 +1045,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -1064,11 +1073,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1263,7 +1273,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(), @@ -1285,7 +1295,7 @@ impl_runtime_apis! { Ok( ( sibling_parachain_location, - NetworkId::Westend, + NetworkId::ByGenesis(WESTEND_GENESIS_HASH), [Parachain(8765)].into() ) ) @@ -1521,6 +1531,15 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } #[cfg(test)] @@ -1529,16 +1548,16 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{SignedExtension, Zero}, + traits::{TransactionExtension, Zero}, }; #[test] - fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + fn ensure_transaction_extension_definition_is_compatible_with_relay() { + use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; sp_io::TestExternalities::default().execute_with(|| { frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); - let payload: SignedExtra = ( + let payload: TxExtension = ( frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), frame_system::CheckTxVersion::new(), @@ -1551,13 +1570,13 @@ mod tests { ( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), ), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::new(false), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); // for BridgeHubRococo { - let bhr_indirect_payload = bp_bridge_hub_rococo::SignedExtension::from_params( + let bhr_indirect_payload = bp_bridge_hub_rococo::TransactionExtension::from_params( VERSION.spec_version, VERSION.transaction_version, bp_runtime::TransactionEra::Immortal, @@ -1568,8 +1587,8 @@ mod tests { ); assert_eq!(payload.encode().split_last().unwrap().1, bhr_indirect_payload.encode()); assert_eq!( - payload.additional_signed().unwrap().encode().split_last().unwrap().1, - bhr_indirect_payload.additional_signed().unwrap().encode() + TxExtension::implicit(&payload).unwrap().encode().split_last().unwrap().1, + sp_runtime::traits::TransactionExtension::::implicit(&bhr_indirect_payload).unwrap().encode() ) } }); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..64eef1b4f740 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --chain=bridge-hub-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_136_000 picoseconds. + Weight::from_parts(5_842_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_771_000 picoseconds. + Weight::from_parts(8_857_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_771_000 picoseconds. + Weight::from_parts(8_857_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 732_000 picoseconds. + Weight::from_parts(2_875_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_627_000 picoseconds. + Weight::from_parts(6_322_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 471_000 picoseconds. + Weight::from_parts(2_455_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 491_000 picoseconds. + Weight::from_parts(2_916_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_798_000 picoseconds. + Weight::from_parts(6_272_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index 517b3eb69fc8..74796e626a2e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -27,6 +27,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_bridge_grandpa; pub mod pallet_bridge_messages_rococo_to_rococo_bulletin; @@ -38,6 +39,7 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..71d17e7259f7 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --chain=bridge-hub-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `3` + // Estimated: `3593` + // Minimum execution time: 34_956_000 picoseconds. + Weight::from_parts(40_788_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..288aac38563c 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -81,11 +84,7 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -133,12 +132,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 +253,10 @@ impl XcmWeightInfo for BridgeHubRococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } + 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..bac73e0e0567 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 set_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 7a0f1462e7a7..8be2993c68f4 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 @@ -21,7 +21,7 @@ use bridge_hub_rococo_runtime::{ bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, - SignedExtra, UncheckedExtrinsic, + TxExtension, UncheckedExtrinsic, }; use codec::{Decode, Encode}; use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; @@ -170,7 +170,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -183,12 +183,12 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::::new(false), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), tx_ext) } fn construct_and_apply_extrinsic( 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 20bd5d129138..2e7dd98e9dce 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 @@ -18,13 +18,11 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_common_config, bridge_to_bulletin_config, - bridge_to_ethereum_config::EthereumGatewayAddress, - bridge_to_westend_config, - xcm_config::{LocationToAccountId, RelayNetwork, TokenLocation, XcmConfig}, + 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, - SignedExtra, TransactionPayment, UncheckedExtrinsic, + TransactionPayment, TxExtension, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; @@ -39,7 +37,7 @@ use sp_runtime::{ 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! { @@ -51,7 +49,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -64,12 +62,13 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::new(false), - ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + ) + .into(); + let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), tx_ext) } fn construct_and_apply_extrinsic( @@ -128,6 +127,9 @@ mod bridge_hub_westend_tests { BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, DeliveryRewardInBalance, RelayersForLegacyLaneIdsMessagesInstance, }; + use bridge_hub_rococo_runtime::{ + bridge_to_ethereum_config::EthereumGatewayAddress, xcm_config::LocationToAccountId, + }; use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ BridgeHubWestendLocation, WestendGlobalConsensusNetwork, @@ -375,7 +377,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::< @@ -409,7 +411,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::< @@ -498,7 +500,10 @@ mod bridge_hub_bulletin_tests { use super::*; use bp_messages::{HashedLaneId, LaneIdType}; use bridge_common_config::BridgeGrandpaRococoBulletinInstance; - use bridge_hub_rococo_runtime::bridge_common_config::RelayersForPermissionlessLanesInstance; + use bridge_hub_rococo_runtime::{ + bridge_common_config::RelayersForPermissionlessLanesInstance, + xcm_config::LocationToAccountId, + }; use bridge_hub_test_utils::test_cases::from_grandpa_chain; use bridge_to_bulletin_config::{ RococoBulletinGlobalConsensusNetwork, RococoBulletinGlobalConsensusNetworkLocation, @@ -638,7 +643,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::< @@ -671,7 +676,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::< @@ -818,9 +823,10 @@ fn location_conversion_works() { let expected = AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); - let got = LocationToAccountHelper::::convert_location( - tc.location.into(), - ) + let got = LocationToAccountHelper::< + AccountId, + bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, + >::convert_location(tc.location.into()) .unwrap(); assert_eq!(got, expected, "{}", tc.description); 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 a0233bf2ea45..637e7c710640 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -43,6 +43,7 @@ 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 } @@ -119,7 +120,6 @@ snowbridge-runtime-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 } -sp-keyring = { workspace = true, default-features = true } snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] @@ -200,6 +200,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -237,6 +238,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm-bridge-hub/runtime-benchmarks", 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 e45654bc62bd..62c93da7c831 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 @@ -38,13 +38,13 @@ use frame_support::{ use frame_system::{EnsureNever, EnsureRoot}; use pallet_bridge_messages::LaneIdOf; use pallet_bridge_relayers::extension::{ - BridgeRelayersSignedExtension, WithMessagesExtensionConfig, + BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, }; use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; 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())] @@ -91,8 +91,9 @@ pub type ToRococoBridgeHubMessagesDeliveryProof = type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher; -/// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersSignedExtension< +/// Transaction extension that refunds relayers that are delivering messages from the Rococo +/// parachain. +pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersTransactionExtension< Runtime, WithMessagesExtensionConfig< StrOnBridgeHubWestendRefundBridgeHubRococoMessages, @@ -203,13 +204,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 @@ -331,7 +334,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]); @@ -339,18 +341,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 0b270e584339..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 parachains_common::{genesis_config_helpers::*, AccountId, AuraId}; -use sp_core::sr25519; +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,101 +59,46 @@ 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![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1002.into(), - Some(get_account_id_from_seed::("Bob")), + Some(Sr25519Keyring::Bob.to_account_id()), westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(), vec![( 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])), )], ), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => bridge_hub_westend_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => bridge_hub_westend_genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1002.into(), - Some(get_account_id_from_seed::("Bob")), + Some(Sr25519Keyring::Bob.to_account_id()), westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(), vec![], ), 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 b73d8e5c67fa..065400016791 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}; @@ -116,8 +119,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -128,13 +131,13 @@ pub type SignedExtra = ( pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages,), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, frame_metadata_hash_extension::CheckMetadataHash, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -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,8 +223,8 @@ 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, impl_version: 0, @@ -283,6 +286,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the transaction extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -343,6 +348,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -589,12 +595,14 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -925,6 +933,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -949,11 +958,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1148,7 +1158,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(), @@ -1170,7 +1180,7 @@ impl_runtime_apis! { Ok( ( sibling_parachain_location, - NetworkId::Rococo, + NetworkId::ByGenesis(ROCOCO_GENESIS_HASH), [Parachain(8765)].into() ) ) @@ -1337,6 +1347,15 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { @@ -1350,16 +1369,16 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{SignedExtension, Zero}, + traits::{TransactionExtension, Zero}, }; #[test] - fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + fn ensure_transaction_extension_definition_is_compatible_with_relay() { + use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; sp_io::TestExternalities::default().execute_with(|| { frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); - let payload: SignedExtra = ( + let payload: TxExtension = ( frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), frame_system::CheckTxVersion::new(), @@ -1372,12 +1391,12 @@ mod tests { ( bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), ), + frame_metadata_hash_extension::CheckMetadataHash::new(false), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), - frame_metadata_hash_extension::CheckMetadataHash::new(false), ); { - let bh_indirect_payload = bp_bridge_hub_westend::SignedExtension::from_params( + let bh_indirect_payload = bp_bridge_hub_westend::TransactionExtension::from_params( VERSION.spec_version, VERSION.transaction_version, bp_runtime::TransactionEra::Immortal, @@ -1388,8 +1407,8 @@ mod tests { ); assert_eq!(payload.encode().split_last().unwrap().1, bh_indirect_payload.encode()); assert_eq!( - payload.additional_signed().unwrap().encode().split_last().unwrap().1, - bh_indirect_payload.additional_signed().unwrap().encode() + TxExtension::implicit(&payload).unwrap().encode().split_last().unwrap().1, + sp_runtime::traits::TransactionExtension::::implicit(&bh_indirect_payload).unwrap().encode() ) } }); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..459b137d3b84 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ +// --chain=bridge-hub-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_166_000 picoseconds. + Weight::from_parts(6_021_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_651_000 picoseconds. + Weight::from_parts(9_177_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_651_000 picoseconds. + Weight::from_parts(9_177_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 601_000 picoseconds. + Weight::from_parts(2_805_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_727_000 picoseconds. + Weight::from_parts(6_051_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 471_000 picoseconds. + Weight::from_parts(2_494_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 521_000 picoseconds. + Weight::from_parts(2_655_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_808_000 picoseconds. + Weight::from_parts(6_402_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs index d60529f9a237..c1c5c337aca8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/mod.rs @@ -27,6 +27,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_bridge_grandpa; pub mod pallet_bridge_messages; @@ -37,6 +38,7 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..92c53b918792 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ +// --chain=bridge-hub-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `3` + // Estimated: `3593` + // Minimum execution time: 40_286_000 picoseconds. + Weight::from_parts(45_816_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..fa1304d11c6f 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -82,11 +85,7 @@ impl XcmWeightInfo for BridgeHubWestendXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -134,12 +133,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 +174,9 @@ impl XcmWeightInfo for BridgeHubWestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -232,4 +257,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..6434f6206fbe 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 set_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 c5f3871c0790..1a1ce2a28ea3 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 @@ -22,7 +22,7 @@ use bp_polkadot_core::Signature; use bridge_hub_westend_runtime::{ bridge_to_rococo_config, xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, UncheckedExtrinsic, + RuntimeCall, RuntimeEvent, SessionKeys, TxExtension, UncheckedExtrinsic, }; use codec::{Decode, Encode}; use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; @@ -171,7 +171,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let extra: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -184,8 +184,8 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::::new(false), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); 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 c5a9b8c53a93..69301b34fe6b 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 @@ -29,7 +29,7 @@ use bridge_hub_westend_runtime::{ xcm_config::{LocationToAccountId, RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - SignedExtra, TransactionPayment, UncheckedExtrinsic, + TransactionPayment, TxExtension, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ BridgeGrandpaRococoInstance, BridgeHubRococoLocation, BridgeParachainRococoInstance, @@ -46,7 +46,7 @@ use sp_runtime::{ 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. @@ -81,7 +81,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -94,12 +94,13 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), - cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), frame_metadata_hash_extension::CheckMetadataHash::new(false), - ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + ) + .into(); + let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), tx_ext) } fn construct_and_apply_extrinsic( @@ -295,7 +296,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::< @@ -329,7 +330,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::< 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/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs index 9c5d6269dc0e..ad6db0b83e80 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().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().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().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().weight, ) .ensure_complete()); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 170d6d226057..e03fc934ceaf 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -50,6 +50,7 @@ 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-offchain = { workspace = true } @@ -123,6 +124,7 @@ runtime-benchmarks = [ "pallet-scheduler/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -228,6 +230,7 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs index 942e0c294dd0..1e8212cf6ac2 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs @@ -333,4 +333,5 @@ impl pallet_treasury::Config for Runtime { sp_core::ConstU8<1>, ConstU32<1000>, >; + type BlockNumberProvider = crate::System; } 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 30a23d7aaea4..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,9 +18,10 @@ use crate::*; use alloc::{vec, vec::Vec}; use cumulus_primitives_core::ParaId; -use parachains_common::{genesis_config_helpers::*, AccountId, AuraId}; -use sp_core::sr25519; +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; const COLLECTIVES_WESTEND_ED: Balance = ExistentialDeposit::get(); @@ -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,60 +55,31 @@ 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![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1001.into(), ), - Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => collectives_westend_genesis( + sp_genesis_builder::DEV_RUNTIME_PRESET => collectives_westend_genesis( // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], 1001.into(), ), diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 7f87d4701f96..c3e105a84fb6 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,8 +123,8 @@ 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, impl_version: 0, @@ -185,6 +185,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -239,6 +240,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -730,8 +732,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -743,7 +745,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// All migrations executed on runtime upgrade as a nested tuple of types implementing /// `OnRuntimeUpgrade`. Included migrations must be idempotent. type Migrations = ( @@ -774,6 +776,7 @@ pub type Executive = frame_executive::Executive< mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -781,6 +784,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1044,6 +1048,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -1056,11 +1061,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1165,6 +1171,15 @@ impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..f32f27303135 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ +// --chain=collectives-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_497_000 picoseconds. + Weight::from_parts(5_961_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_240_000 picoseconds. + Weight::from_parts(8_175_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_240_000 picoseconds. + Weight::from_parts(8_175_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(3_005_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_426_000 picoseconds. + Weight::from_parts(6_131_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_715_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 491_000 picoseconds. + Weight::from_parts(2_635_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_958_000 picoseconds. + Weight::from_parts(6_753_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs index a9a298e547ed..00b3bd92d5ef 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -18,6 +18,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_alliance; pub mod pallet_asset_rate; pub mod pallet_balances; @@ -39,6 +40,7 @@ pub mod pallet_salary_fellowship_salary; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..5d077b89d564 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ +// --chain=collectives-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 39_815_000 picoseconds. + Weight::from_parts(46_067_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..56ef2e8ba02f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -33,7 +33,7 @@ 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, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, @@ -50,7 +50,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(); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index dfa75b8d3cf3..c98ca7ba3e74 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -161,6 +161,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index e8cc9d02fb0e..40801f66a47b 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -72,7 +72,10 @@ impl Config for Runtime { type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; type MaxDelegateDependencies = ConstU32<32>; type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; - type Migrations = (pallet_contracts::migration::v16::Migration,); + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = (); + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_contracts::migration::codegen::BenchMigrations; type RuntimeHoldReason = RuntimeHoldReason; type Debug = (); type Environment = (); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 3377802e91de..f661a8bdccfe 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, @@ -87,8 +87,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -101,7 +101,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -141,8 +141,8 @@ 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, impl_version: 0, @@ -250,6 +250,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } parameter_types! { @@ -434,6 +435,7 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -757,6 +759,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -769,11 +772,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -879,6 +883,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { 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 80417ea00362..a38b7400cfa3 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -163,6 +163,7 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs index 76ee06a87e8d..d76ac443a147 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs @@ -134,7 +134,6 @@ 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(), }, ]); @@ -164,7 +163,6 @@ 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(), }, ]); @@ -193,7 +191,6 @@ 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(), }, ]); @@ -218,6 +215,36 @@ impl CoretimeInterface for CoretimeAllocator { end_hint: Option>, ) { use crate::coretime::CoretimeProviderCalls::AssignCore; + + // The relay chain currently only allows `assign_core` to be called with a complete mask + // and only ever with increasing `begin`. The assignments must be truncated to avoid + // dropping that core's assignment completely. + + // This shadowing of `assignment` is temporary and can be removed when the relay can accept + // multiple messages to assign a single core. + let assignment = if assignment.len() > 28 { + let mut total_parts = 0u16; + // Account for missing parts with a new `Idle` assignment at the start as + // `assign_core` on the relay assumes this is sorted. We'll add the rest of the + // assignments and sum the parts in one pass, so this is just initialized to 0. + let mut assignment_truncated = vec![(CoreAssignment::Idle, 0)]; + // Truncate to first 27 non-idle assignments. + assignment_truncated.extend( + assignment + .into_iter() + .filter(|(a, _)| *a != CoreAssignment::Idle) + .take(27) + .inspect(|(_, parts)| total_parts += *parts) + .collect::>(), + ); + + // Set the parts of the `Idle` assignment we injected at the start of the vec above. + assignment_truncated[0].1 = 57_600u16.saturating_sub(total_parts); + assignment_truncated + } else { + assignment + }; + let assign_core_call = RelayRuntimePallets::Coretime(AssignCore(core, begin, assignment, end_hint)); @@ -228,7 +255,6 @@ 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(), }, ]); diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index f16dae04f217..31700c2e25ff 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, }; @@ -98,8 +98,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -114,7 +114,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -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,8 +147,8 @@ 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, impl_version: 0, @@ -208,6 +209,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -265,6 +268,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -588,6 +592,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 @@ -915,7 +938,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; @@ -1148,6 +1171,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..a4d09696a1a1 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ +// --chain=coretime-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs index 216f41a5a666..24c4f50e6ab8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs @@ -22,6 +22,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_broker; pub mod pallet_collator_selection; @@ -30,6 +31,7 @@ pub mod pallet_multisig; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..29d48abab895 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ +// --chain=coretime-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..f69736e31451 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -81,11 +84,7 @@ impl XcmWeightInfo for CoretimeRococoXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -132,12 +131,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 +251,10 @@ impl XcmWeightInfo for CoretimeRococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } + 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..d207c09ffcd8 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 set_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-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 25bf777047d0..149fa5d0b045 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -161,6 +161,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs index 865ff68d4c65..f0c03849750a 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs @@ -127,12 +127,6 @@ impl CoretimeInterface for CoretimeAllocator { use crate::coretime::CoretimeProviderCalls::RequestCoreCount; let request_core_count_call = RelayRuntimePallets::Coretime(RequestCoreCount(count)); - // Weight for `request_core_count` from westend benchmarks: - // `ref_time` = 7889000 + (3 * 25000000) + (1 * 100000000) = 182889000 - // `proof_size` = 1636 - // Add 5% to each component and round to 2 significant figures. - let call_weight = Weight::from_parts(190_000_000, 1700); - let message = Xcm(vec![ Instruction::UnpaidExecution { weight_limit: WeightLimit::Unlimited, @@ -140,7 +134,6 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: call_weight, call: request_core_count_call.encode().into(), }, ]); @@ -170,7 +163,6 @@ 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(), }, ]); @@ -199,7 +191,6 @@ 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(), }, ]); @@ -224,15 +215,39 @@ impl CoretimeInterface for CoretimeAllocator { end_hint: Option>, ) { use crate::coretime::CoretimeProviderCalls::AssignCore; + + // The relay chain currently only allows `assign_core` to be called with a complete mask + // and only ever with increasing `begin`. The assignments must be truncated to avoid + // dropping that core's assignment completely. + + // This shadowing of `assignment` is temporary and can be removed when the relay can accept + // multiple messages to assign a single core. + let assignment = if assignment.len() > 28 { + let mut total_parts = 0u16; + // Account for missing parts with a new `Idle` assignment at the start as + // `assign_core` on the relay assumes this is sorted. We'll add the rest of the + // assignments and sum the parts in one pass, so this is just initialized to 0. + let mut assignment_truncated = vec![(CoreAssignment::Idle, 0)]; + // Truncate to first 27 non-idle assignments. + assignment_truncated.extend( + assignment + .into_iter() + .filter(|(a, _)| *a != CoreAssignment::Idle) + .take(27) + .inspect(|(_, parts)| total_parts += *parts) + .collect::>(), + ); + + // Set the parts of the `Idle` assignment we injected at the start of the vec above. + assignment_truncated[0].1 = 57_600u16.saturating_sub(total_parts); + assignment_truncated + } else { + assignment + }; + let assign_core_call = RelayRuntimePallets::Coretime(AssignCore(core, begin, assignment, end_hint)); - // Weight for `assign_core` from westend benchmarks: - // `ref_time` = 10177115 + (1 * 25000000) + (2 * 100000000) + (57600 * 13932) = 937660315 - // `proof_size` = 3612 - // Add 5% to each component and round to 2 significant figures. - let call_weight = Weight::from_parts(980_000_000, 3800); - let message = Xcm(vec![ Instruction::UnpaidExecution { weight_limit: WeightLimit::Unlimited, @@ -240,7 +255,6 @@ impl CoretimeInterface for CoretimeAllocator { }, Instruction::Transact { origin_kind: OriginKind::Native, - require_weight_at_most: call_weight, call: assign_core_call.encode().into(), }, ]); diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index e909b804587f..1f0f54884fa8 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, }; @@ -98,8 +98,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -114,15 +114,17 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( pallet_collator_selection::migration::v2::MigrationToV2, cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, pallet_broker::migration::MigrateV0ToV1, pallet_broker::migration::MigrateV1ToV2, pallet_broker::migration::MigrateV2ToV3, + pallet_broker::migration::MigrateV3ToV4, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -145,8 +147,8 @@ 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, impl_version: 0, @@ -207,6 +209,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -265,6 +269,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -582,6 +587,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 @@ -906,7 +930,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; @@ -1140,6 +1164,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..d928b73613a3 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ +// --chain=coretime-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs index 216f41a5a666..24c4f50e6ab8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs @@ -22,6 +22,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_broker; pub mod pallet_collator_selection; @@ -30,6 +31,7 @@ pub mod pallet_multisig; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..f159f877afe7 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ +// --chain=coretime-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..1640baa38c99 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -80,11 +83,7 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -132,12 +131,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 +172,9 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -229,4 +254,7 @@ impl XcmWeightInfo for CoretimeWestendXcmWeight { 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..fb6e4631736d 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,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-westend-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_688_000 picoseconds. - Weight::from_parts(24_845_000, 3571) + // Minimum execution time: 29_463_000 picoseconds. + Weight::from_parts(30_178_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: 569_000 picoseconds. - Weight::from_parts(619_000, 0) + // Minimum execution time: 568_000 picoseconds. + Weight::from_parts(608_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_585_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_851_000 picoseconds. - Weight::from_parts(6_061_000, 3497) + // Minimum execution time: 7_400_000 picoseconds. + Weight::from_parts(7_572_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_951_000 picoseconds. + Weight::from_parts(7_173_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_245_000 picoseconds. + Weight::from_parts(1_342_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: 613_000 picoseconds. + Weight::from_parts(657_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: 613_000 picoseconds. + Weight::from_parts(656_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: 570_000 picoseconds. + Weight::from_parts(608_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: 557_000 picoseconds. + Weight::from_parts(607_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: 557_000 picoseconds. + Weight::from_parts(578_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: 21_146_000 picoseconds. - Weight::from_parts(21_771_000, 3571) + // Minimum execution time: 26_179_000 picoseconds. + Weight::from_parts(27_089_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_446_000 picoseconds. - Weight::from_parts(8_660_000, 3555) + // Minimum execution time: 10_724_000 picoseconds. + Weight::from_parts(10_896_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: 561_000 picoseconds. - Weight::from_parts(594_000, 0) + // Minimum execution time: 567_000 picoseconds. + Weight::from_parts(623_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_953_000 picoseconds. - Weight::from_parts(20_608_000, 3539) + // Minimum execution time: 24_367_000 picoseconds. + Weight::from_parts(25_072_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_290_000 picoseconds. - Weight::from_parts(2_370_000, 0) + // Minimum execution time: 2_554_000 picoseconds. + Weight::from_parts(2_757_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: 922_000 picoseconds. + Weight::from_parts(992_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: 688_000 picoseconds. + Weight::from_parts(723_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: 607_000 picoseconds. + Weight::from_parts(647_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: 591_000 picoseconds. + Weight::from_parts(620_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: 735_000 picoseconds. + Weight::from_parts(802_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_953_000 picoseconds. - Weight::from_parts(25_516_000, 3571) + // Minimum execution time: 29_923_000 picoseconds. + Weight::from_parts(30_770_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: 2_746_000 picoseconds. - Weight::from_parts(2_944_000, 0) + // Minimum execution time: 2_884_000 picoseconds. + Weight::from_parts(3_088_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_325_000 picoseconds. - Weight::from_parts(21_942_000, 3571) + // Minimum execution time: 26_632_000 picoseconds. + Weight::from_parts(27_228_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: 600_000 picoseconds. - Weight::from_parts(631_000, 0) + // Minimum execution time: 599_000 picoseconds. + Weight::from_parts(655_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: 587_000 picoseconds. + Weight::from_parts(628_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: 572_000 picoseconds. + Weight::from_parts(631_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: 570_000 picoseconds. + Weight::from_parts(615_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: 624_000 picoseconds. + Weight::from_parts(659_000, 0) + } + pub fn set_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-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 1205be95c932..9f38975efae6 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/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::*, WESTEND_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 TokenRelayLocation: 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(); @@ -185,6 +186,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/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index bc76f174b507..fdf467ab64b8 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,8 +99,8 @@ 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, impl_version: 0, @@ -290,8 +290,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( pallet_sudo::CheckOnlySudoAccount, frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, @@ -303,7 +303,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -318,6 +318,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [cumulus_pallet_parachain_system, ParachainSystem] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_glutton, Glutton] [pallet_message_queue, MessageQueue] [pallet_timestamp, Timestamp] @@ -447,6 +448,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -458,11 +460,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..4fbbb8d6f781 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,130 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/ +// --chain=glutton-westend-dev-1300 + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_908_000 picoseconds. + Weight::from_parts(4_007_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_510_000 picoseconds. + Weight::from_parts(6_332_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_510_000 picoseconds. + Weight::from_parts(6_332_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 651_000 picoseconds. + Weight::from_parts(851_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_387_000 picoseconds. + Weight::from_parts(3_646_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 491_000 picoseconds. + Weight::from_parts(651_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 451_000 picoseconds. + Weight::from_parts(662_000, 0) + .saturating_add(Weight::from_parts(0, 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: 3_537_000 picoseconds. + Weight::from_parts(4_208_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} 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 c969bb2985bd..34458c2352fb 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -30,6 +30,7 @@ pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } pallet-session = { workspace = true } @@ -104,6 +105,7 @@ std = [ "pallet-collator-selection/std", "pallet-identity/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-multisig/std", "pallet-proxy/std", "pallet-session/std", @@ -154,9 +156,11 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -184,6 +188,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", "pallet-session/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 aa04d01cf037..25356a84806d 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, @@ -91,8 +91,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -106,7 +106,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -134,8 +134,8 @@ 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, impl_version: 0, @@ -189,9 +189,11 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_timestamp::Config for Runtime { @@ -241,6 +243,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -534,6 +537,25 @@ impl identity_migrator::Config for Runtime { type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -569,6 +591,9 @@ construct_runtime!( // The main stage. Identity: pallet_identity = 50, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // To migrate deposits IdentityMigrator: identity_migrator = 248, } @@ -587,6 +612,8 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_migrations, MultiBlockMigrations] + [pallet_transaction_payment, TransactionPayment] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus @@ -859,7 +886,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; @@ -1059,6 +1086,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs index 8211447d68c8..690bb974bd17 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs @@ -36,6 +36,7 @@ parameter_types! { // 17 | Min size without `IdentityInfo` (accounted for in byte deposit) pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = deposit(1, 53); pub RelayTreasuryAccount: AccountId = parachains_common::TREASURY_PALLET_ID.into_account_truncating(); @@ -46,6 +47,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = ConstU32<100>; type IdentityInformation = IdentityInfo; @@ -57,6 +59,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 3 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..fb2b69e23e82 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ +// --chain=people-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs index dce959e817be..fab3c629ab3f 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs @@ -20,14 +20,17 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_multisig; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs index 1e8ba87e2510..dfc522ab3b51 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs @@ -340,7 +340,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, 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() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -368,7 +368,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -392,18 +392,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..61857ac8202a --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs @@ -0,0 +1,172 @@ +// 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. + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .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`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_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: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // 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())) + .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()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..555fd5a32fa8 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ +// --chain=people-rococo-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..631cc7b7f0b0 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -80,11 +83,7 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -131,12 +130,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 +250,10 @@ impl XcmWeightInfo for PeopleRococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } + 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..6aac6119e7ec 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 set_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-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 64e956d8b6b5..6840b97d8c3f 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -30,6 +30,7 @@ pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } pallet-session = { workspace = true } @@ -104,6 +105,7 @@ std = [ "pallet-collator-selection/std", "pallet-identity/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-multisig/std", "pallet-proxy/std", "pallet-session/std", @@ -154,9 +156,11 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -184,6 +188,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", "pallet-session/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 c8131c94f15b..1c5183636c49 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, @@ -91,8 +91,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The transactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -106,7 +106,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -133,8 +133,8 @@ 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, impl_version: 0, @@ -188,9 +188,11 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_timestamp::Config for Runtime { @@ -240,6 +242,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -533,6 +536,25 @@ impl identity_migrator::Config for Runtime { type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -568,6 +590,9 @@ construct_runtime!( // The main stage. Identity: pallet_identity = 50, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // To migrate deposits IdentityMigrator: identity_migrator = 248, } @@ -586,6 +611,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_migrations, MultiBlockMigrations] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus @@ -858,7 +884,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; @@ -1058,6 +1084,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/people.rs b/cumulus/parachains/runtimes/people/people-westend/src/people.rs index 0255fd074b11..47551f6d4bdc 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/people.rs @@ -36,6 +36,7 @@ parameter_types! { // 17 | Min size without `IdentityInfo` (accounted for in byte deposit) pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = deposit(1, 53); pub RelayTreasuryAccount: AccountId = parachains_common::TREASURY_PALLET_ID.into_account_truncating(); @@ -46,6 +47,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = ConstU32<100>; type IdentityInformation = IdentityInfo; @@ -57,6 +59,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 3 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..0a4b9e8e2681 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ +// --chain=people-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs index dce959e817be..fab3c629ab3f 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs @@ -20,14 +20,17 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_multisig; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs index 1e8ba87e2510..dfc522ab3b51 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs @@ -340,7 +340,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, 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() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -368,7 +368,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -392,18 +392,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..61857ac8202a --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs @@ -0,0 +1,172 @@ +// 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. + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .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`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_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: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // 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())) + .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()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..30e4524e586e --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ +// --chain=people-westend-dev + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// 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: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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..4b51a3ba411b 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,10 @@ 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 xcm::{ + latest::{prelude::*, AssetTransferFilter}, + DoubleEncoded, +}; trait WeighAssets { fn weigh_assets(&self, weight: Weight) -> Weight; @@ -80,11 +83,7 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmFungibleWeight::::transfer_reserve_asset()) } - fn transact( - _origin_type: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_type: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -131,12 +130,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() } @@ -228,4 +250,10 @@ impl XcmWeightInfo for PeopleWestendXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } + 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..36400f2c1e66 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,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-westend-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_537_000 picoseconds. - Weight::from_parts(30_513_000, 3535) + // Minimum execution time: 29_015_000 picoseconds. + Weight::from_parts(30_359_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: 683_000 picoseconds. - Weight::from_parts(738_000, 0) + // Minimum execution time: 572_000 picoseconds. + Weight::from_parts(637_000, 0) + } + pub fn pay_fees() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_550_000 picoseconds. + Weight::from_parts(1_604_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_498_000 picoseconds. - Weight::from_parts(7_904_000, 3497) + // Minimum execution time: 7_354_000 picoseconds. + Weight::from_parts(7_808_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_716_000 picoseconds. + Weight::from_parts(7_067_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_280_000 picoseconds. + Weight::from_parts(1_355_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: 587_000 picoseconds. + Weight::from_parts(645_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: 629_000 picoseconds. + Weight::from_parts(662_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: 590_000 picoseconds. + Weight::from_parts(639_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: 651_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: 670_000 picoseconds. - Weight::from_parts(712_000, 0) + // Minimum execution time: 601_000 picoseconds. + Weight::from_parts(630_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: 26_405_000 picoseconds. - Weight::from_parts(26_877_000, 3535) + // Minimum execution time: 25_650_000 picoseconds. + Weight::from_parts(26_440_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_953_000 picoseconds. - Weight::from_parts(11_345_000, 3555) + // Minimum execution time: 10_492_000 picoseconds. + Weight::from_parts(10_875_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: 644_000 picoseconds. - Weight::from_parts(693_000, 0) + // Minimum execution time: 597_000 picoseconds. + Weight::from_parts(647_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: 24_157_000 picoseconds. - Weight::from_parts(24_980_000, 3503) + // Minimum execution time: 23_732_000 picoseconds. + Weight::from_parts(24_290_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_767_000 picoseconds. - Weight::from_parts(2_844_000, 0) + // Minimum execution time: 2_446_000 picoseconds. + Weight::from_parts(2_613_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: 960_000 picoseconds. + Weight::from_parts(1_045_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: 703_000 picoseconds. + Weight::from_parts(739_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: 616_000 picoseconds. + Weight::from_parts(651_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: 621_000 picoseconds. + Weight::from_parts(660_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: 794_000 picoseconds. + Weight::from_parts(831_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: 30_222_000 picoseconds. - Weight::from_parts(31_110_000, 3535) + // Minimum execution time: 29_527_000 picoseconds. + Weight::from_parts(30_614_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_108_000 picoseconds. - Weight::from_parts(3_325_000, 0) + // Minimum execution time: 3_189_000 picoseconds. + Weight::from_parts(3_296_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_548_000 picoseconds. - Weight::from_parts(26_911_000, 3535) + // Minimum execution time: 25_965_000 picoseconds. + Weight::from_parts(26_468_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: 684_000 picoseconds. - Weight::from_parts(726_000, 0) + // Minimum execution time: 618_000 picoseconds. + Weight::from_parts(659_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: 593_000 picoseconds. + Weight::from_parts(618_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: 603_000 picoseconds. + Weight::from_parts(634_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: 568_000 picoseconds. + Weight::from_parts(629_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: 598_000 picoseconds. + Weight::from_parts(655_000, 0) + } + pub fn set_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-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index bec5b923d8ad..25256495ef91 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/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::*, WESTEND_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::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(); diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 3b38eee244f1..05ecf6ca8e81 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -441,15 +441,11 @@ 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(), - }, + Transact { origin_kind: OriginKind::Superuser, call: call.into() }, ExpectTransactStatus(MaybeErrorCode::Success), ]); @@ -473,11 +469,7 @@ impl< 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().weight, - call: call.encode().into(), - }, + Transact { origin_kind: OriginKind::Xcm, call: call.encode().into() }, ExpectTransactStatus(MaybeErrorCode::Success), ]); diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs index 1c58df189b67..a66163154cf6 100644 --- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs @@ -72,17 +72,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,19 +119,10 @@ 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(); diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 96338b645581..3a6b9d42f211 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -79,6 +79,7 @@ pallet-collator-selection = { 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", @@ -162,11 +164,13 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/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", diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index 05773846164f..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; @@ -92,7 +93,7 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::{ latest::prelude::{AssetId as AssetLocationId, BodyId}, - VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, + VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, }; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -129,8 +130,8 @@ pub type BlockId = generic::BlockId; // Id used for identifying assets. pub type AssetId = u32; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -143,7 +144,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Migrations = ( pallet_balances::migration::MigrateToTrackInactive, @@ -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, @@ -435,6 +436,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = (); } parameter_types! { @@ -493,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; @@ -745,6 +750,19 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = (); } +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_asset_tx_payment::BenchmarkHelperTrait for AssetTxHelper { + fn create_asset_id_parameter(_id: u32) -> (u32, u32) { + unimplemented!("Penpal uses default weights"); + } + fn setup_balances_and_pool(_asset_id: u32, _account: AccountId) { + unimplemented!("Penpal uses default weights"); + } +} + impl pallet_asset_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; @@ -757,6 +775,9 @@ impl pallet_asset_tx_payment::Config for Runtime { >, AssetsToBlockAuthor, >; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetTxHelper; } impl pallet_sudo::Config for Runtime { @@ -807,6 +828,7 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_session, SessionBench::] @@ -1087,6 +1109,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; let mut list = Vec::::new(); @@ -1098,11 +1121,12 @@ 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; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime {} use cumulus_pallet_session_benchmarking::Pallet as SessionBench; @@ -1143,6 +1167,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { 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 9c905c876277..b0581c8d43ff 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -49,7 +49,7 @@ polkadot-runtime-common = { workspace = true } # Cumulus cumulus-pallet-aura-ext = { workspace = true } pallet-message-queue = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true } +cumulus-pallet-parachain-system = { workspace = true, features = ["experimental-ump-signals"] } cumulus-pallet-xcm = { workspace = true } cumulus-pallet-xcmp-queue = { workspace = true } cumulus-ping = { workspace = true } @@ -126,6 +126,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 5abdc995c00d..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, @@ -267,6 +267,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = (); } impl pallet_sudo::Config for Runtime { @@ -331,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(); @@ -655,8 +656,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -669,7 +670,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, diff --git a/cumulus/polkadot-omni-node/Cargo.toml b/cumulus/polkadot-omni-node/Cargo.toml new file mode 100644 index 000000000000..a736e1ef80c5 --- /dev/null +++ b/cumulus/polkadot-omni-node/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "polkadot-omni-node" +version = "0.1.0" +authors.workspace = true +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" + +[lints] +workspace = true + +[dependencies] +color-eyre = { workspace = true } + +# Local +polkadot-omni-node-lib = { workspace = true } + +[build-dependencies] +substrate-build-script-utils = { workspace = true, default-features = true } + +[features] +default = [] +runtime-benchmarks = [ + "polkadot-omni-node-lib/runtime-benchmarks", +] +try-runtime = [ + "polkadot-omni-node-lib/try-runtime", +] diff --git a/cumulus/polkadot-omni-node/README.md b/cumulus/polkadot-omni-node/README.md new file mode 100644 index 000000000000..d87b3b63c407 --- /dev/null +++ b/cumulus/polkadot-omni-node/README.md @@ -0,0 +1,65 @@ +# Polkadot Omni Node + +This is a white labeled implementation based on [`polkadot-omni-node-lib`](https://crates.io/crates/polkadot-omni-node-lib). +It can be used to start a parachain node from a provided chain spec file. It is only compatible with runtimes that use block +number `u32` and `Aura` consensus. + +## Installation + +Download & expose it via `PATH`: + +```bash +# Download and set it on PATH. +wget https://github.com/paritytech/polkadot-sdk/releases/download//polkadot-omni-node +chmod +x polkadot-omni-node +export PATH="$PATH:`pwd`" +``` + +Compile & install via `cargo`: + +```bash +# Assuming ~/.cargo/bin is on the PATH +cargo install polkadot-omni-node +``` + +## Usage + +A basic example for an Omni Node run starts from a runtime which implements the [`sp_genesis_builder::GenesisBuilder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html). +The interface mandates the runtime to expose a [`named-preset`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/#generate-chain-spec-using-runtime-provided-genesis-config-preset). + +### 1. Install chain-spec-builder + +**Note**: `chain-spec-builder` binary is published on [`crates.io`](https://crates.io) under +[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict. +Install it with `cargo` like bellow : + +```bash +cargo install staging-chain-spec-builder +``` + +### 2. Generate a chain spec + +Omni Node expects for the chain spec to contain parachains related fields like `relay_chain` and `para_id`. +These fields can be introduced by running [`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) +with additional flags: + +```bash +chain-spec-builder create --relay-chain --para-id -r named-preset +``` + +### 3. Run Omni Node + +And now with the generated chain spec we can start Omni Node like so: + +```bash +polkadot-omni-node --chain +``` + +## Useful links + +* [`Omni Node Polkadot SDK Docs`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) +* [`Chain Spec Genesis Reference Docs`](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/chain_spec_genesis/index.html) +* [`polkadot-parachain-bin`](https://crates.io/crates/polkadot-parachain-bin) +* [`polkadot-sdk-parachain-template`](https://github.com/paritytech/polkadot-sdk-parachain-template) +* [`frame-omni-bencher`](https://crates.io/crates/frame-omni-bencher) +* [`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) diff --git a/cumulus/polkadot-omni-node/build.rs b/cumulus/polkadot-omni-node/build.rs new file mode 100644 index 000000000000..8c498735eae9 --- /dev/null +++ b/cumulus/polkadot-omni-node/build.rs @@ -0,0 +1,22 @@ +// 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 substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; + +fn main() { + generate_cargo_keys(); + rerun_if_git_head_changed(); +} diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml b/cumulus/polkadot-omni-node/lib/Cargo.toml similarity index 98% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml rename to cumulus/polkadot-omni-node/lib/Cargo.toml index 5e4c9fcf1a3d..a690229f1695 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/Cargo.toml +++ b/cumulus/polkadot-omni-node/lib/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "polkadot-parachain-lib" +name = "polkadot-omni-node-lib" version = "0.1.0" authors.workspace = true edition.workspace = true @@ -105,6 +105,7 @@ runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/cumulus/polkadot-omni-node/lib/README.md b/cumulus/polkadot-omni-node/lib/README.md new file mode 100644 index 000000000000..5789a35a1016 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/README.md @@ -0,0 +1,26 @@ +# Polkadot Omni Node Library + +Helper library that can be used to run a parachain node. + +## Overview + +This library can be used to run a parachain node while also customizing the chain specs +that are supported by default by the `--chain-spec` argument of the node's `CLI` +and the parameters of the runtime that is associated with each of these chain specs. + +## API + +The library exposes the possibility to provide a [`RunConfig`]. Through this structure +2 optional configurations can be provided: +- a chain spec loader (an implementation of [`chain_spec::LoadSpec`]): this can be used for + providing the chain specs that are supported by default by the `--chain-spec` argument of the + node's `CLI` and the actual chain config associated with each one. +- a runtime resolver (an implementation of [`runtime::RuntimeResolver`]): this can be used for + providing the parameters of the runtime that is associated with each of the chain specs + +Apart from this, a [`CliConfig`] can also be provided, that can be used to customize some +user-facing binary author, support url, etc. + +## Examples + +For an example, see the [`polkadot-parachain-bin`](https://crates.io/crates/polkadot-parachain-bin) crate. diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs b/cumulus/polkadot-omni-node/lib/src/cli.rs similarity index 97% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs rename to cumulus/polkadot-omni-node/lib/src/cli.rs index 6ca328912bba..dc59c185d909 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/cli.rs +++ b/cumulus/polkadot-omni-node/lib/src/cli.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +//! CLI options of the omni-node. See [`Command`]. + use crate::{ chain_spec::DiskChainSpecLoader, common::{ @@ -103,6 +105,7 @@ pub enum Subcommand { Benchmark(frame_benchmarking_cli::BenchmarkCmd), } +/// CLI Options shipped with `polkadot-omni-node`. #[derive(clap::Parser)] #[command( propagate_version = true, @@ -113,9 +116,11 @@ pub struct Cli { #[arg(skip)] pub(crate) chain_spec_loader: Option>, + /// Possible subcommands. See [`Subcommand`]. #[command(subcommand)] pub subcommand: Option, + /// The shared parameters with all cumulus-based parachain nodes. #[command(flatten)] pub run: cumulus_client_cli::RunCmd, @@ -200,6 +205,7 @@ impl SubstrateCli for Cli { } } +/// The relay chain CLI flags. These are passed in after a `--` at the end. #[derive(Debug)] pub struct RelayChainCli { /// The actual relay chain cli object. diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs b/cumulus/polkadot-omni-node/lib/src/command.rs similarity index 95% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs rename to cumulus/polkadot-omni-node/lib/src/command.rs index 350dcfee1cdb..cf283819966f 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/command.rs +++ b/cumulus/polkadot-omni-node/lib/src/command.rs @@ -48,6 +48,16 @@ pub struct RunConfig { pub runtime_resolver: Box, } +impl RunConfig { + /// Create a new `RunConfig` + pub fn new( + runtime_resolver: Box, + chain_spec_loader: Box, + ) -> Self { + RunConfig { chain_spec_loader, runtime_resolver } + } +} + pub fn new_aura_node_spec( aura_id: AuraConsensusId, extra_args: &NodeExtraArgs, @@ -266,13 +276,15 @@ pub fn run(cmd_config: RunConfig) -> Result<() } let hwbench = (!cli.no_hardware_benchmarks) - .then_some(config.database.path().map(|database_path| { - let _ = std::fs::create_dir_all(database_path); - sc_sysinfo::gather_hwbench( - Some(database_path), - &SUBSTRATE_REFERENCE_HARDWARE, - ) - })) + .then(|| { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(database_path); + sc_sysinfo::gather_hwbench( + Some(database_path), + &SUBSTRATE_REFERENCE_HARDWARE, + ) + }) + }) .flatten(); let parachain_account = diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/aura.rs b/cumulus/polkadot-omni-node/lib/src/common/aura.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/aura.rs rename to cumulus/polkadot-omni-node/lib/src/common/aura.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/chain_spec.rs b/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/chain_spec.rs rename to cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs b/cumulus/polkadot-omni-node/lib/src/common/command.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/command.rs rename to cumulus/polkadot-omni-node/lib/src/common/command.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/mod.rs b/cumulus/polkadot-omni-node/lib/src/common/mod.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/mod.rs rename to cumulus/polkadot-omni-node/lib/src/common/mod.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/rpc.rs b/cumulus/polkadot-omni-node/lib/src/common/rpc.rs similarity index 93% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/rpc.rs rename to cumulus/polkadot-omni-node/lib/src/common/rpc.rs index 85665c9b220f..4879bd1eb7f4 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/rpc.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/rpc.rs @@ -46,7 +46,7 @@ impl BuildRpcExtensions< ParachainClient, ParachainBackend, - sc_transaction_pool::FullPool>, + sc_transaction_pool::TransactionPoolHandle>, > for BuildParachainRpcExtensions where RuntimeApi: @@ -57,7 +57,9 @@ where fn build_rpc_extensions( client: Arc>, backend: Arc>, - pool: Arc>>, + pool: Arc< + sc_transaction_pool::TransactionPoolHandle>, + >, ) -> sc_service::error::Result { let build = || -> Result> { let mut module = RpcExtension::new(()); diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/runtime.rs b/cumulus/polkadot-omni-node/lib/src/common/runtime.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/runtime.rs rename to cumulus/polkadot-omni-node/lib/src/common/runtime.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs similarity index 95% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs rename to cumulus/polkadot-omni-node/lib/src/common/spec.rs index dca28b3c28f7..259f89049c92 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/spec.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs @@ -40,7 +40,7 @@ use sc_service::{Configuration, ImportQueue, PartialComponents, TaskManager}; use sc_sysinfo::HwBench; use sc_telemetry::{TelemetryHandle, TelemetryWorker}; use sc_tracing::tracing::Instrument; -use sc_transaction_pool::FullPool; +use sc_transaction_pool::TransactionPoolHandle; use sp_keystore::KeystorePtr; use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; @@ -65,7 +65,7 @@ where telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc>>, keystore: KeystorePtr, relay_chain_slot_duration: Duration, para_id: ParaId, @@ -149,12 +149,15 @@ pub(crate) trait BaseNodeSpec { telemetry }); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); @@ -184,7 +187,7 @@ pub(crate) trait NodeSpec: BaseNodeSpec { type BuildRpcExtensions: BuildRpcExtensions< ParachainClient, ParachainBackend, - FullPool>, + TransactionPoolHandle>, >; type StartConsensus: StartConsensus; @@ -236,7 +239,7 @@ pub(crate) trait NodeSpec: BaseNodeSpec { 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, @@ -343,8 +346,6 @@ pub(crate) trait NodeSpec: BaseNodeSpec { )?; } - start_network.start_network(); - Ok(task_manager) } .instrument(sc_tracing::tracing::info_span!( diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs b/cumulus/polkadot-omni-node/lib/src/common/types.rs similarity index 95% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs rename to cumulus/polkadot-omni-node/lib/src/common/types.rs index 9cfdcb22451c..4bc58dc9db7e 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/common/types.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/types.rs @@ -20,7 +20,7 @@ use sc_consensus::DefaultImportQueue; use sc_executor::WasmExecutor; use sc_service::{PartialComponents, TFullBackend, TFullClient}; use sc_telemetry::{Telemetry, TelemetryWorkerHandle}; -use sc_transaction_pool::FullPool; +use sc_transaction_pool::TransactionPoolHandle; use sp_runtime::{generic, traits::BlakeTwo256}; use std::sync::Arc; @@ -51,6 +51,6 @@ pub type ParachainService = PartialComponents< ParachainBackend, (), DefaultImportQueue, - FullPool>, + TransactionPoolHandle>, (ParachainBlockImport, Option, Option), >; diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/mod.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/mod.rs rename to cumulus/polkadot-omni-node/lib/src/fake_runtime_api/mod.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/utils.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs similarity index 98% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/fake_runtime_api/utils.rs rename to cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs index 0b1ed5d82889..6bfd5f4f4cbd 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-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/lib.rs b/cumulus/polkadot-omni-node/lib/src/lib.rs new file mode 100644 index 000000000000..ccc1b542b253 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/lib.rs @@ -0,0 +1,28 @@ +// 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 . + +#![doc = include_str!("../README.md")] +#![deny(missing_docs)] + +pub mod cli; +mod command; +mod common; +mod fake_runtime_api; +mod nodes; + +pub use cli::CliConfig; +pub use command::{run, RunConfig}; +pub use common::{chain_spec, runtime}; diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/aura.rs b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs similarity index 98% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/aura.rs rename to cumulus/polkadot-omni-node/lib/src/nodes/aura.rs index cf1ee91cbab5..ec5d0a439ec4 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/aura.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs @@ -52,7 +52,7 @@ use sc_consensus::{ }; use sc_service::{Configuration, Error, TaskManager}; use sc_telemetry::TelemetryHandle; -use sc_transaction_pool::FullPool; +use sc_transaction_pool::TransactionPoolHandle; use sp_api::ProvideRuntimeApi; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; @@ -291,7 +291,7 @@ where telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc>>, keystore: KeystorePtr, _relay_chain_slot_duration: Duration, para_id: ParaId, @@ -387,7 +387,7 @@ where telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>>, + transaction_pool: Arc>>, keystore: KeystorePtr, relay_chain_slot_duration: Duration, para_id: ParaId, diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/manual_seal.rs b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs similarity index 90% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/manual_seal.rs rename to cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs index d00d7adf27e1..7e36ce735af3 100644 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/manual_seal.rs +++ b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs @@ -25,10 +25,9 @@ use cumulus_primitives_core::ParaId; 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_runtime::traits::Header; -use sp_timestamp::Timestamp; use std::{marker::PhantomData, sync::Arc}; pub struct ManualSealNode(PhantomData); @@ -86,7 +85,7 @@ impl ManualSealNode { // 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()), ); @@ -94,17 +93,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(), @@ -113,7 +102,7 @@ impl ManualSealNode { import_queue, net_config, block_announce_validator_builder: None, - syncing_strategy, + warp_sync_config: None, block_relay: None, metrics, })?; @@ -182,7 +171,10 @@ impl ManualSealNode { additional_key_values: None, }; Ok(( - sp_timestamp::InherentDataProvider::new(Timestamp::new(0)), + // This is intentional, as the runtime that we expect to run against this + // will never receive the aura-related inherents/digests, and providing + // real timestamps would cause aura <> timestamp checking to fail. + sp_timestamp::InherentDataProvider::new(sp_timestamp::Timestamp::new(0)), mocked_parachain, )) } @@ -227,7 +219,6 @@ impl ManualSealNode { telemetry: telemetry.as_mut(), })?; - start_network.start_network(); Ok(task_manager) } } diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/mod.rs b/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/mod.rs rename to cumulus/polkadot-omni-node/lib/src/nodes/mod.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/benchmark_storage_works.rs b/cumulus/polkadot-omni-node/lib/src/tests/benchmark_storage_works.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/benchmark_storage_works.rs rename to cumulus/polkadot-omni-node/lib/src/tests/benchmark_storage_works.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/common.rs b/cumulus/polkadot-omni-node/lib/src/tests/common.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/common.rs rename to cumulus/polkadot-omni-node/lib/src/tests/common.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/polkadot_argument_parsing.rs b/cumulus/polkadot-omni-node/lib/src/tests/polkadot_argument_parsing.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/polkadot_argument_parsing.rs rename to cumulus/polkadot-omni-node/lib/src/tests/polkadot_argument_parsing.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/polkadot_mdns_issue.rs b/cumulus/polkadot-omni-node/lib/src/tests/polkadot_mdns_issue.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/polkadot_mdns_issue.rs rename to cumulus/polkadot-omni-node/lib/src/tests/polkadot_mdns_issue.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/purge_chain_works.rs b/cumulus/polkadot-omni-node/lib/src/tests/purge_chain_works.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/purge_chain_works.rs rename to cumulus/polkadot-omni-node/lib/src/tests/purge_chain_works.rs diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/running_the_node_and_interrupt.rs b/cumulus/polkadot-omni-node/lib/src/tests/running_the_node_and_interrupt.rs similarity index 100% rename from cumulus/polkadot-parachain/polkadot-parachain-lib/src/tests/running_the_node_and_interrupt.rs rename to cumulus/polkadot-omni-node/lib/src/tests/running_the_node_and_interrupt.rs diff --git a/cumulus/polkadot-omni-node/src/main.rs b/cumulus/polkadot-omni-node/src/main.rs new file mode 100644 index 000000000000..a6c1dd3cadbb --- /dev/null +++ b/cumulus/polkadot-omni-node/src/main.rs @@ -0,0 +1,54 @@ +// 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 . + +//! White labeled polkadot omni-node. +//! +//! For documentation, see [`polkadot_omni_node_lib`]. + +#![warn(missing_docs)] +#![warn(unused_extern_crates)] + +use polkadot_omni_node_lib::{ + chain_spec::DiskChainSpecLoader, run, runtime::DefaultRuntimeResolver, CliConfig as CliConfigT, + RunConfig, +}; + +struct CliConfig; + +impl CliConfigT for CliConfig { + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/paritytech/polkadot-sdk/issues/new".into() + } + + fn copyright_start_year() -> u16 { + 2017 + } +} + +fn main() -> color_eyre::eyre::Result<()> { + color_eyre::install()?; + + let config = RunConfig::new(Box::new(DefaultRuntimeResolver), Box::new(DiskChainSpecLoader)); + Ok(run::(config)?) +} diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index fb95853c492a..5520126d0742 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -22,7 +22,7 @@ serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } # Local -polkadot-parachain-lib = { features = ["rococo-native", "westend-native"], workspace = true } +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 } @@ -37,13 +37,10 @@ penpal-runtime = { workspace = true } people-rococo-runtime = { workspace = true } people-westend-runtime = { workspace = true } parachains-common = { workspace = true, default-features = true } -testnet-parachains-constants = { features = [ - "rococo", - "westend", -], workspace = true } # Substrate sp-core = { workspace = true, default-features = true } +sp-keyring = { 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 } @@ -55,9 +52,6 @@ xcm = { workspace = true, default-features = true } # Cumulus cumulus-primitives-core = { workspace = true, default-features = true } -# Bridges -bp-messages = { workspace = true, default-features = true } - [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } @@ -66,7 +60,7 @@ default = [] runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "parachains-common/runtime-benchmarks", - "polkadot-parachain-lib/runtime-benchmarks", + "polkadot-omni-node-lib/runtime-benchmarks", "sc-service/runtime-benchmarks", "asset-hub-rococo-runtime/runtime-benchmarks", @@ -84,7 +78,7 @@ runtime-benchmarks = [ "rococo-parachain-runtime/runtime-benchmarks", ] try-runtime = [ - "polkadot-parachain-lib/try-runtime", + "polkadot-omni-node-lib/try-runtime", "asset-hub-rococo-runtime/try-runtime", "asset-hub-westend-runtime/try-runtime", diff --git a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs b/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs deleted file mode 100644 index a293ab225c6f..000000000000 --- a/cumulus/polkadot-parachain/polkadot-parachain-lib/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -// 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 . - -//! Helper library that can be used to run a parachain node. -//! -//! ## Overview -//! -//! This library can be used to run a parachain node while also customizing the chain specs -//! that are supported by default by the `--chain-spec` argument of the node's `CLI` -//! and the parameters of the runtime that is associated with each of these chain specs. -//! -//! ## API -//! -//! The library exposes the possibility to provide a [`RunConfig`]. Through this structure -//! 2 optional configurations can be provided: -//! - a chain spec loader (an implementation of [`chain_spec::LoadSpec`]): this can be used for -//! providing the chain specs that are supported by default by the `--chain-spec` argument of the -//! node's `CLI` and the actual chain config associated with each one. -//! - a runtime resolver (an implementation of [`runtime::RuntimeResolver`]): this can be used for -//! providing the parameters of the runtime that is associated with each of the chain specs -//! -//! Apart from this, a [`CliConfig`] can also be provided, that can be used to customize some -//! user-facing binary author, support url, etc. -//! -//! ## Examples -//! -//! For an example, see the `polkadot-parachain-bin` crate. - -#![deny(missing_docs)] - -mod cli; -mod command; -mod common; -mod fake_runtime_api; -mod nodes; - -pub use cli::CliConfig; -pub use command::{run, RunConfig}; -pub use common::{chain_spec, runtime}; diff --git a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs index 699c0b5ce775..ec2afc743de8 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; pub fn asset_hub_westend_development_config() -> GenericChainSpec { diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index af399be9eacf..839e93d0a67b 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -15,7 +15,7 @@ // along with Cumulus. If not, see . use cumulus_primitives_core::ParaId; -use polkadot_parachain_lib::chain_spec::GenericChainSpec; +use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::{ChainSpec, ChainType}; use std::str::FromStr; @@ -127,7 +127,7 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup pub mod rococo { use super::{ChainType, ParaId}; - use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; pub(crate) const BRIDGE_HUB_ROCOCO: &str = "bridge-hub-rococo"; pub(crate) const BRIDGE_HUB_ROCOCO_LOCAL: &str = "bridge-hub-rococo-local"; @@ -175,7 +175,7 @@ pub mod kusama { /// Sub-module for Westend setup. pub mod westend { use super::{ChainType, ParaId}; - use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; pub(crate) const BRIDGE_HUB_WESTEND: &str = "bridge-hub-westend"; pub(crate) const BRIDGE_HUB_WESTEND_LOCAL: &str = "bridge-hub-westend-local"; diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index 227e15fdff8d..0d2f66b5acc0 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; /// Collectives Westend Development Config. diff --git a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs index fec3f56e6d35..fa865d7458cb 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs @@ -15,7 +15,7 @@ // along with Cumulus. If not, see . use cumulus_primitives_core::ParaId; -use polkadot_parachain_lib::chain_spec::GenericChainSpec; +use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::{ChainSpec, ChainType}; use std::{borrow::Cow, str::FromStr}; @@ -146,13 +146,11 @@ pub fn chain_type_name(chain_type: &ChainType) -> Cow { /// Sub-module for Rococo setup. pub mod rococo { use super::{chain_type_name, CoretimeRuntimeType, ParaId}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId, Balance}; - use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; pub(crate) const CORETIME_ROCOCO: &str = "coretime-rococo"; pub(crate) const CORETIME_ROCOCO_LOCAL: &str = "coretime-rococo-local"; @@ -187,15 +185,12 @@ pub mod rococo { .with_chain_type(chain_type) .with_genesis_config_patch(genesis( // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], para_id, )) @@ -235,7 +230,7 @@ pub mod rococo { "safeXcmVersion": Some(SAFE_XCM_VERSION), }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, }) } @@ -244,12 +239,10 @@ pub mod rococo { /// Sub-module for Westend setup. pub mod westend { use super::{chain_type_name, CoretimeRuntimeType, GenericChainSpec, ParaId}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId, Balance}; - use polkadot_parachain_lib::chain_spec::Extensions; - use sp_core::sr25519; + use polkadot_omni_node_lib::chain_spec::Extensions; + use sp_keyring::Sr25519Keyring; pub(crate) const CORETIME_WESTEND: &str = "coretime-westend"; pub(crate) const CORETIME_WESTEND_LOCAL: &str = "coretime-westend-local"; @@ -277,15 +270,12 @@ pub mod westend { .with_chain_type(chain_type) .with_genesis_config_patch(genesis( // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], para_id, )) diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 136411b93e8b..ddfb961370ac 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -14,14 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::get_account_id_from_seed; use cumulus_primitives_core::ParaId; use parachains_common::AuraId; -use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; -use sp_core::sr25519; - -use super::get_collator_keys_from_seed; +use sp_keyring::Sr25519Keyring; fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { serde_json::json!( { @@ -29,7 +26,7 @@ fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json:: "parachainId": parachain_id }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, "aura": { "authorities": collators }, }) @@ -45,7 +42,7 @@ pub fn glutton_westend_development_config(para_id: ParaId) -> GenericChainSpec { .with_chain_type(ChainType::Local) .with_genesis_config_patch(glutton_genesis( para_id, - vec![get_collator_keys_from_seed::("Alice")], + vec![Sr25519Keyring::Alice.public().into()], )) .build() } @@ -60,10 +57,7 @@ pub fn glutton_westend_local_config(para_id: ParaId) -> GenericChainSpec { .with_chain_type(ChainType::Local) .with_genesis_config_patch(glutton_genesis( para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], + vec![Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into()], )) .build() } @@ -81,10 +75,7 @@ pub fn glutton_westend_config(para_id: ParaId) -> GenericChainSpec { .with_chain_type(ChainType::Live) .with_genesis_config_patch(glutton_westend_genesis( para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], + vec![Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into()], )) .with_protocol_id(format!("glutton-westend-{}", para_id).as_str()) .with_properties(properties) @@ -97,7 +88,7 @@ fn glutton_westend_genesis(parachain_id: ParaId, collators: Vec) -> serd "parachainId": parachain_id }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, "aura": { "authorities": collators }, }) diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index 16fdbdc38656..00dceabb0069 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -15,10 +15,7 @@ // along with Cumulus. If not, see . use cumulus_primitives_core::ParaId; -pub(crate) use parachains_common::genesis_config_helpers::{ - get_account_id_from_seed, get_collator_keys_from_seed, get_from_seed, -}; -use polkadot_parachain_lib::{ +use polkadot_omni_node_lib::{ chain_spec::{GenericChainSpec, LoadSpec}, runtime::{ AuraConsensusId, BlockNumber, Consensus, Runtime, RuntimeResolver as RuntimeResolverT, @@ -274,7 +271,7 @@ mod tests { use super::*; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, ChainType, Extension}; use serde::{Deserialize, Serialize}; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; #[derive( Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default, @@ -310,12 +307,9 @@ mod tests { .with_id(id) .with_chain_type(ChainType::Local) .with_genesis_config_patch(crate::chain_spec::rococo_parachain::testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - ], - vec![get_account_id_from_seed::("Alice")], + Sr25519Keyring::Alice.to_account_id(), + vec![Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into()], + vec![Sr25519Keyring::Bob.to_account_id()], 1000.into(), )) .build() diff --git a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs index 5645bf06b67b..b60b9982c49e 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION}; +use crate::chain_spec::SAFE_XCM_VERSION; use cumulus_primitives_core::ParaId; use parachains_common::{AccountId, AuraId}; -use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; -use sp_core::sr25519; +use sp_keyring::Sr25519Keyring; pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> GenericChainSpec { // Give your base currency a unit name and decimal places @@ -41,29 +41,10 @@ pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> GenericChainSpec .with_genesis_config_patch(penpal_testnet_genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), id, )) .build() @@ -105,7 +86,7 @@ fn penpal_testnet_genesis( "safeXcmVersion": Some(SAFE_XCM_VERSION), }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/people.rs b/cumulus/polkadot-parachain/src/chain_spec/people.rs index 3c1150d95422..1735a904b8ea 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/people.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/people.rs @@ -16,7 +16,7 @@ use cumulus_primitives_core::ParaId; use parachains_common::Balance as PeopleBalance; -use polkadot_parachain_lib::chain_spec::GenericChainSpec; +use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::ChainSpec; use std::str::FromStr; @@ -120,13 +120,11 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup. pub mod rococo { use super::{ParaId, PeopleBalance}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId}; - use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; pub(crate) const PEOPLE_ROCOCO: &str = "people-rococo"; pub(crate) const PEOPLE_ROCOCO_LOCAL: &str = "people-rococo-local"; @@ -155,29 +153,10 @@ pub mod rococo { .with_genesis_config_patch(genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), para_id, )) .with_properties(properties) @@ -230,13 +209,11 @@ pub mod rococo { /// Sub-module for Westend setup. pub mod westend { use super::{ParaId, PeopleBalance}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId}; - use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; pub(crate) const PEOPLE_WESTEND: &str = "people-westend"; pub(crate) const PEOPLE_WESTEND_LOCAL: &str = "people-westend-local"; @@ -265,29 +242,10 @@ pub mod westend { .with_genesis_config_patch(genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), para_id, )) .with_properties(properties) diff --git a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs index 251926838d24..68383ac5c233 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs @@ -16,14 +16,15 @@ //! ChainSpecs dedicated to Rococo parachain setups (for testing and example purposes) -use crate::chain_spec::{get_from_seed, SAFE_XCM_VERSION}; +use crate::chain_spec::SAFE_XCM_VERSION; use cumulus_primitives_core::ParaId; use hex_literal::hex; -use parachains_common::{genesis_config_helpers::get_account_id_from_seed, AccountId}; -use polkadot_parachain_lib::chain_spec::{Extensions, GenericChainSpec}; +use parachains_common::AccountId; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use rococo_parachain_runtime::AuraId; use sc_chain_spec::ChainType; -use sp_core::{crypto::UncheckedInto, sr25519}; +use sp_core::crypto::UncheckedInto; +use sp_keyring::Sr25519Keyring; pub fn rococo_parachain_local_config() -> GenericChainSpec { GenericChainSpec::builder( @@ -34,22 +35,12 @@ pub fn rococo_parachain_local_config() -> GenericChainSpec { .with_id("local_testnet") .with_chain_type(ChainType::Local) .with_genesis_config_patch(testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![get_from_seed::("Alice"), get_from_seed::("Bob")], + Sr25519Keyring::Alice.to_account_id(), vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + AuraId::from(Sr25519Keyring::Alice.public()), + AuraId::from(Sr25519Keyring::Bob.public()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1000.into(), )) .build() diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index f2dce552c51a..61764636a060 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -21,7 +21,7 @@ mod chain_spec; -use polkadot_parachain_lib::{run, CliConfig as CliConfigT, RunConfig}; +use polkadot_omni_node_lib::{run, CliConfig as CliConfigT, RunConfig}; struct CliConfig; @@ -46,9 +46,9 @@ impl CliConfigT for CliConfig { fn main() -> color_eyre::eyre::Result<()> { color_eyre::install()?; - let config = RunConfig { - chain_spec_loader: Box::new(chain_spec::ChainSpecLoader), - runtime_resolver: Box::new(chain_spec::RuntimeResolver), - }; + let config = RunConfig::new( + Box::new(chain_spec::RuntimeResolver), + Box::new(chain_spec::ChainSpecLoader), + ); Ok(run::(config)?) } diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index 6bad65b3ff2c..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 = 1; - /// Information about a collation. /// /// This was used in version 1 of the [`CollectCollationInfo`] runtime api. diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 3a98fdd017ae..e1ae6743335a 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -14,6 +14,7 @@ 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 } @@ -24,8 +25,8 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true } docify = { workspace = true } [dev-dependencies] -sp-trie = { workspace = true } sp-io = { workspace = true } +sp-trie = { workspace = true } cumulus-test-runtime = { workspace = true } [features] @@ -34,6 +35,7 @@ std = [ "codec/std", "cumulus-primitives-core/std", "cumulus-primitives-proof-size-hostfunction/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs index 2529297691e8..5cbe662e2700 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -30,11 +30,15 @@ use frame_support::{ use frame_system::Config; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension}, transaction_validity::TransactionValidityError, DispatchResult, }; +#[cfg(test)] +mod tests; + const LOG_TARGET: &'static str = "runtime::storage_reclaim"; /// `StorageWeightReclaimer` is a mechanism for manually reclaiming storage weight. @@ -43,7 +47,7 @@ const LOG_TARGET: &'static str = "runtime::storage_reclaim"; /// reclaim it computes the real consumed storage weight and refunds excess weight. /// /// # Example -#[doc = docify::embed!("src/lib.rs", simple_reclaimer_example)] +#[doc = docify::embed!("src/tests.rs", simple_reclaimer_example)] pub struct StorageWeightReclaimer { previous_remaining_proof_size: u64, previous_reported_proof_size: Option, @@ -119,43 +123,35 @@ impl core::fmt::Debug for StorageWeightReclaim { } } -impl SignedExtension for StorageWeightReclaim +impl TransactionExtension for StorageWeightReclaim where T::RuntimeCall: Dispatchable, { const IDENTIFIER: &'static str = "StorageWeightReclaim"; - - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); + type Val = (); type Pre = Option; - fn additional_signed( - &self, - ) -> Result - { - Ok(()) - } - - fn pre_dispatch( + fn prepare( self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, + _val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> Result { + ) -> Result { Ok(get_proof_size()) } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, _len: usize, _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - let Some(Some(pre_dispatch_proof_size)) = pre else { - return Ok(()); + ) -> Result { + let Some(pre_dispatch_proof_size) = pre else { + return Ok(Weight::zero()); }; let Some(post_dispatch_proof_size) = get_proof_size() else { @@ -163,13 +159,13 @@ where target: LOG_TARGET, "Proof recording enabled during pre-dispatch, now disabled. This should not happen." ); - return Ok(()) + return Ok(Weight::zero()) }; // Unspent weight according to the `actual_weight` from `PostDispatchInfo` // This unspent weight will be refunded by the `CheckWeight` extension, so we need to // account for that. let unspent = post_info.calc_unspent(info).proof_size(); - let benchmarked_weight = info.weight.proof_size().saturating_sub(unspent); + let benchmarked_weight = info.total_weight().proof_size().saturating_sub(unspent); let consumed_weight = post_dispatch_proof_size.saturating_sub(pre_dispatch_proof_size); let storage_size_diff = benchmarked_weight.abs_diff(consumed_weight as u64); @@ -202,685 +198,15 @@ 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." ); current.accrue(Weight::from_parts(0, missing_from_node), info.class); } }); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::marker::PhantomData; - use frame_support::{ - assert_ok, - dispatch::{DispatchClass, PerDispatchClass}, - weights::{Weight, WeightMeter}, - }; - use frame_system::{BlockWeight, CheckWeight}; - use sp_runtime::{AccountId32, BuildStorage}; - use sp_trie::proof_size_extension::ProofSizeExt; - - type Test = cumulus_test_runtime::Runtime; - const CALL: &::RuntimeCall = - &cumulus_test_runtime::RuntimeCall::System(frame_system::Call::set_heap_pages { - pages: 0u64, - }); - const ALICE: AccountId32 = AccountId32::new([1u8; 32]); - const LEN: usize = 150; - - pub fn new_test_ext() -> sp_io::TestExternalities { - let ext: sp_io::TestExternalities = cumulus_test_runtime::RuntimeGenesisConfig::default() - .build_storage() - .unwrap() - .into(); - ext - } - - struct TestRecorder { - return_values: Box<[usize]>, - counter: std::sync::atomic::AtomicUsize, - } - - impl TestRecorder { - fn new(values: &[usize]) -> Self { - TestRecorder { return_values: values.into(), counter: Default::default() } - } - } - - impl sp_trie::ProofSizeProvider for TestRecorder { - fn estimate_encoded_size(&self) -> usize { - let counter = self.counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed); - self.return_values[counter] - } - } - - fn setup_test_externalities(proof_values: &[usize]) -> sp_io::TestExternalities { - let mut test_ext = new_test_ext(); - let test_recorder = TestRecorder::new(proof_values); - test_ext.register_extension(ProofSizeExt::new(test_recorder)); - test_ext - } - - fn set_current_storage_weight(new_weight: u64) { - BlockWeight::::mutate(|current_weight| { - current_weight.set(Weight::from_parts(0, new_weight), DispatchClass::Normal); - }); - } - - fn get_storage_weight() -> PerDispatchClass { - BlockWeight::::get() - } - - #[test] - fn basic_refund() { - // The real cost will be 100 bytes of storage size - let mut test_ext = setup_test_externalities(&[0, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 500 - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Should add 500 + 150 (len) to weight. - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(0)); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - // We expect a refund of 400 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1250); - }) - } - - #[test] - fn underestimating_refund() { - // We fixed a bug where `pre dispatch info weight > consumed weight > post info weight` - // resulted in error. - - // The real cost will be 100 bytes of storage size - let mut test_ext = setup_test_externalities(&[0, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 500 - let info = DispatchInfo { weight: Weight::from_parts(0, 101), ..Default::default() }; - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(0, 99)), - pays_fee: Default::default(), - }; - - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(0)); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - // We expect an accrue of 1 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1250); - }) - } - - #[test] - fn sets_to_node_storage_proof_if_higher() { - // The storage proof reported by the proof recorder is higher than what is stored on - // the runtime side. - { - let mut test_ext = setup_test_externalities(&[1000, 1005]); - - test_ext.execute_with(|| { - // Stored in BlockWeight is 5 - set_current_storage_weight(5); - - // Benchmarked storage weight: 10 - let info = DispatchInfo { weight: Weight::from_parts(0, 10), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(1000)); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // We expect that the storage weight was set to the node-side proof size (1005) + - // extrinsics length (150) - assert_eq!(get_storage_weight().total().proof_size(), 1155); - }) - } - - // In this second scenario the proof size on the node side is only lower - // after reclaim happened. - { - let mut test_ext = setup_test_externalities(&[175, 180]); - test_ext.execute_with(|| { - set_current_storage_weight(85); - - // Benchmarked storage weight: 100 - let info = - DispatchInfo { weight: Weight::from_parts(0, 100), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // After this pre_dispatch, the BlockWeight proof size will be - // 85 (initial) + 100 (benched) + 150 (tx length) = 335 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(175)); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - - // First we will reclaim 95, which leaves us with 240 BlockWeight. This is lower - // than 180 (proof size hf) + 150 (length), so we expect it to be set to 330. - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // We expect that the storage weight was set to the node-side proof weight - assert_eq!(get_storage_weight().total().proof_size(), 330); - }) - } - } - - #[test] - fn does_nothing_without_extension() { - let mut test_ext = new_test_ext(); - - // Proof size extension not registered - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 500 - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Adds 500 + 150 (len) weight - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, None); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1650); - }) - } - - #[test] - fn negative_refund_is_added_to_weight() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 100 - let info = DispatchInfo { weight: Weight::from_parts(0, 100), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Weight added should be 100 + 150 (len) - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // We expect no refund - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!( - get_storage_weight().total().proof_size(), - 1100 + LEN as u64 + info.weight.proof_size() - ); - }) - } - - #[test] - fn test_zero_proof_size() { - let mut test_ext = setup_test_externalities(&[0, 0]); - - test_ext.execute_with(|| { - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(0)); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // Proof size should be exactly equal to extrinsic length - assert_eq!(get_storage_weight().total().proof_size(), LEN as u64); - }); - } - - #[test] - fn test_larger_pre_dispatch_proof_size() { - let mut test_ext = setup_test_externalities(&[300, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(1300); - - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Adds 500 + 150 (len) weight, total weight is 1950 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(300)); - - // Refund 500 unspent weight according to `post_info`, total weight is now 1650 - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - // Recorded proof size is negative -200, total weight is now 1450 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1450); - }); - } - - #[test] - fn test_incorporates_check_weight_unspent_weight() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 300 - let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; - - // Actual weight is 50 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 250)), - pays_fee: Default::default(), - }; - - // Should add 300 + 150 (len) of weight - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // Reclaimed 100 - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn test_incorporates_check_weight_unspent_weight_on_negative() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 50 - let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - - // Actual weight is 25 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 25)), - pays_fee: Default::default(), - }; - - // Adds 50 + 150 (len) weight, total weight 1200 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - - // Refunds unspent 25 weight according to `post_info`, 1175 - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - // Adds 200 - 25 (unspent) == 175 weight, total weight 1350 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn test_nothing_relcaimed() { - let mut test_ext = setup_test_externalities(&[0, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(0); - // Benchmarked storage weight: 100 - let info = DispatchInfo { weight: Weight::from_parts(100, 100), ..Default::default() }; - - // Actual proof size is 100 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 100)), - pays_fee: Default::default(), - }; - - // Adds benchmarked weight 100 + 150 (len), total weight is now 250 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - // Weight should go up by 150 len + 100 proof size weight, total weight 250 - assert_eq!(get_storage_weight().total().proof_size(), 250); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - // Should return `setup_test_externalities` proof recorder value: 100. - assert_eq!(pre, Some(0)); - - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - // Nothing to refund, unspent is 0, total weight 250 - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, LEN, &Ok(()))); - // `setup_test_externalities` proof recorder value: 200, so this means the extrinsic - // actually used 100 proof size. - // Nothing to refund or add, weight matches proof recorder - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // Check block len weight was not reclaimed: - // 100 weight + 150 extrinsic len == 250 proof size - assert_eq!(get_storage_weight().total().proof_size(), 250); - }) - } - - #[test] - fn test_incorporates_check_weight_unspent_weight_reverse_order() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 300 - let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; - - // Actual weight is 50 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 250)), - pays_fee: Default::default(), - }; - - // Adds 300 + 150 (len) weight, total weight 1450 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // This refunds 100 - 50(unspent), total weight is now 1400 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - - // Above call refunds 50 (unspent), total weight is 1350 now - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 50 - let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - - // Actual weight is 25 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 25)), - pays_fee: Default::default(), - }; - - // Adds 50 + 150 (len) weight, total weight is 1200 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // Adds additional 150 weight recorded - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn storage_size_reported_correctly() { - let mut test_ext = setup_test_externalities(&[1000]); - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), Some(1000)); - }); - - let mut test_ext = new_test_ext(); - - let test_recorder = TestRecorder::new(&[0]); - - test_ext.register_extension(ProofSizeExt::new(test_recorder)); - - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), Some(0)); - }); - } - - #[test] - fn storage_size_disabled_reported_correctly() { - let mut test_ext = setup_test_externalities(&[PROOF_RECORDING_DISABLED as usize]); - - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), None); - }); - } - - #[test] - fn test_reclaim_helper() { - let mut test_ext = setup_test_externalities(&[1000, 1300, 1800]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 2000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - remaining_weight_meter.consume(Weight::from_parts(0, 500)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 200))); - - remaining_weight_meter.consume(Weight::from_parts(0, 800)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - assert_eq!(reclaimed, Some(Weight::from_parts(0, 300))); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1200)); - }); + Ok(Weight::zero()) } - #[test] - fn test_reclaim_helper_does_not_reclaim_negative() { - // Benchmarked weight does not change at all - let mut test_ext = setup_test_externalities(&[1000, 1300]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1000)); - }); - - // Benchmarked weight increases less than storage proof consumes - let mut test_ext = setup_test_externalities(&[1000, 1300]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - remaining_weight_meter.consume(Weight::from_parts(0, 0)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); - }); - } - - /// Just here for doc purposes - fn get_benched_weight() -> Weight { - Weight::from_parts(0, 5) - } - - /// Just here for doc purposes - fn do_work() {} - - #[docify::export_content(simple_reclaimer_example)] - fn reclaim_with_weight_meter() { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(10, 10)); - - let benched_weight = get_benched_weight(); - - // It is important to instantiate the `StorageWeightReclaimer` before we consume the weight - // for a piece of work from the weight meter. - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - - if remaining_weight_meter.try_consume(benched_weight).is_ok() { - // Perform some work that takes has `benched_weight` storage weight. - do_work(); - - // Reclaimer will detect that we only consumed 2 bytes, so 3 bytes are reclaimed. - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - // We reclaimed 3 bytes of storage size! - assert_eq!(reclaimed, Some(Weight::from_parts(0, 3))); - assert_eq!(get_storage_weight().total().proof_size(), 10); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(10, 8)); - } - } - - #[test] - fn test_reclaim_helper_works_with_meter() { - // The node will report 12 - 10 = 2 consumed storage size between the calls. - let mut test_ext = setup_test_externalities(&[10, 12]); - - test_ext.execute_with(|| { - // Initial storage size is 10. - set_current_storage_weight(10); - reclaim_with_weight_meter(); - }); - } + impl_tx_ext_default!(T::RuntimeCall; weight validate); } diff --git a/cumulus/primitives/storage-weight-reclaim/src/tests.rs b/cumulus/primitives/storage-weight-reclaim/src/tests.rs new file mode 100644 index 000000000000..ab83762cc0db --- /dev/null +++ b/cumulus/primitives/storage-weight-reclaim/src/tests.rs @@ -0,0 +1,706 @@ +// 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::{ + assert_ok, + dispatch::{DispatchClass, PerDispatchClass}, + weights::{Weight, WeightMeter}, +}; +use frame_system::{BlockWeight, CheckWeight}; +use sp_runtime::{traits::DispatchTransaction, AccountId32, BuildStorage}; +use sp_trie::proof_size_extension::ProofSizeExt; + +type Test = cumulus_test_runtime::Runtime; +const CALL: &::RuntimeCall = + &cumulus_test_runtime::RuntimeCall::System(frame_system::Call::set_heap_pages { pages: 0u64 }); +const ALICE: AccountId32 = AccountId32::new([1u8; 32]); +const LEN: usize = 150; + +fn new_test_ext() -> sp_io::TestExternalities { + let ext: sp_io::TestExternalities = cumulus_test_runtime::RuntimeGenesisConfig::default() + .build_storage() + .unwrap() + .into(); + ext +} + +struct TestRecorder { + return_values: Box<[usize]>, + counter: core::sync::atomic::AtomicUsize, +} + +impl TestRecorder { + fn new(values: &[usize]) -> Self { + TestRecorder { return_values: values.into(), counter: Default::default() } + } +} + +impl sp_trie::ProofSizeProvider for TestRecorder { + fn estimate_encoded_size(&self) -> usize { + let counter = self.counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + self.return_values[counter] + } +} + +fn setup_test_externalities(proof_values: &[usize]) -> sp_io::TestExternalities { + let mut test_ext = new_test_ext(); + let test_recorder = TestRecorder::new(proof_values); + test_ext.register_extension(ProofSizeExt::new(test_recorder)); + test_ext +} + +fn set_current_storage_weight(new_weight: u64) { + BlockWeight::::mutate(|current_weight| { + current_weight.set(Weight::from_parts(0, new_weight), DispatchClass::Normal); + }); +} + +fn get_storage_weight() -> PerDispatchClass { + BlockWeight::::get() +} + +#[test] +fn basic_refund() { + // The real cost will be 100 bytes of storage size + let mut test_ext = setup_test_externalities(&[0, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Should add 500 + 150 (len) to weight. + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + // We expect a refund of 400 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1250); + }) +} + +#[test] +fn underestimating_refund() { + // We fixed a bug where `pre dispatch info weight > consumed weight > post info weight` + // resulted in error. + + // The real cost will be 100 bytes of storage size + let mut test_ext = setup_test_externalities(&[0, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { call_weight: Weight::from_parts(0, 101), ..Default::default() }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(0, 99)), + pays_fee: Default::default(), + }; + + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()))); + // We expect an accrue of 1 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()) + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1250); + }) +} + +#[test] +fn sets_to_node_storage_proof_if_higher() { + // The storage proof reported by the proof recorder is higher than what is stored on + // the runtime side. + { + let mut test_ext = setup_test_externalities(&[1000, 1005]); + + test_ext.execute_with(|| { + // Stored in BlockWeight is 5 + set_current_storage_weight(5); + + // Benchmarked storage weight: 10 + let info = + DispatchInfo { call_weight: Weight::from_parts(0, 10), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(1000)); + + assert_ok!(CheckWeight::::post_dispatch_details( + (), + &info, + &post_info, + 0, + &Ok(()) + )); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()) + )); + + // We expect that the storage weight was set to the node-side proof size (1005) + + // extrinsics length (150) + assert_eq!(get_storage_weight().total().proof_size(), 1155); + }) + } + + // In this second scenario the proof size on the node side is only lower + // after reclaim happened. + { + let mut test_ext = setup_test_externalities(&[175, 180]); + test_ext.execute_with(|| { + set_current_storage_weight(85); + + // Benchmarked storage weight: 100 + let info = + DispatchInfo { call_weight: Weight::from_parts(0, 100), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // After this pre_dispatch, the BlockWeight proof size will be + // 85 (initial) + 100 (benched) + 150 (tx length) = 335 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(175)); + + assert_ok!(CheckWeight::::post_dispatch_details( + (), + &info, + &post_info, + 0, + &Ok(()) + )); + + // First we will reclaim 95, which leaves us with 240 BlockWeight. This is lower + // than 180 (proof size hf) + 150 (length), so we expect it to be set to 330. + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()) + )); + + // We expect that the storage weight was set to the node-side proof weight + assert_eq!(get_storage_weight().total().proof_size(), 330); + }) + } +} + +#[test] +fn does_nothing_without_extension() { + let mut test_ext = new_test_ext(); + + // Proof size extension not registered + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Adds 500 + 150 (len) weight + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, None); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1650); + }) +} + +#[test] +fn negative_refund_is_added_to_weight() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 100 + let info = DispatchInfo { call_weight: Weight::from_parts(0, 100), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Weight added should be 100 + 150 (len) + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(100)); + + // We expect no refund + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!( + get_storage_weight().total().proof_size(), + 1100 + LEN as u64 + info.total_weight().proof_size() + ); + }) +} + +#[test] +fn test_zero_proof_size() { + let mut test_ext = setup_test_externalities(&[0, 0]); + + test_ext.execute_with(|| { + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + // Proof size should be exactly equal to extrinsic length + assert_eq!(get_storage_weight().total().proof_size(), LEN as u64); + }); +} + +#[test] +fn test_larger_pre_dispatch_proof_size() { + let mut test_ext = setup_test_externalities(&[300, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1300); + + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Adds 500 + 150 (len) weight, total weight is 1950 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(300)); + + // Refund 500 unspent weight according to `post_info`, total weight is now 1650 + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + // Recorded proof size is negative -200, total weight is now 1450 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1450); + }); +} + +#[test] +fn test_incorporates_check_weight_unspent_weight() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 300 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 300), ..Default::default() }; + + // Actual weight is 50 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 250)), + pays_fee: Default::default(), + }; + + // Should add 300 + 150 (len) of weight + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(100)); + + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + // Reclaimed 100 + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn test_incorporates_check_weight_unspent_weight_on_negative() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 50 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 50), ..Default::default() }; + + // Actual weight is 25 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 25)), + pays_fee: Default::default(), + }; + + // Adds 50 + 150 (len) weight, total weight 1200 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(100)); + + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + // Refunds unspent 25 weight according to `post_info`, 1175 + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + // Adds 200 - 25 (unspent) == 175 weight, total weight 1350 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn test_nothing_relcaimed() { + let mut test_ext = setup_test_externalities(&[0, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(0); + // Benchmarked storage weight: 100 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 100), ..Default::default() }; + + // Actual proof size is 100 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 100)), + pays_fee: Default::default(), + }; + + // Adds benchmarked weight 100 + 150 (len), total weight is now 250 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + // Weight should go up by 150 len + 100 proof size weight, total weight 250 + assert_eq!(get_storage_weight().total().proof_size(), 250); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .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)); + + // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + // Nothing to refund, unspent is 0, total weight 250 + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, LEN, &Ok(()))); + // `setup_test_externalities` proof recorder value: 200, so this means the extrinsic + // actually used 100 proof size. + // Nothing to refund or add, weight matches proof recorder + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()) + )); + + // Check block len weight was not reclaimed: + // 100 weight + 150 extrinsic len == 250 proof size + assert_eq!(get_storage_weight().total().proof_size(), 250); + }) +} + +#[test] +fn test_incorporates_check_weight_unspent_weight_reverse_order() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 300 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 300), ..Default::default() }; + + // Actual weight is 50 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 250)), + pays_fee: Default::default(), + }; + + // Adds 300 + 150 (len) weight, total weight 1450 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(100)); + + // This refunds 100 - 50(unspent), total weight is now 1400 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + // `CheckWeight` gets called after `StorageWeightReclaim` this time. + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + + // Above call refunds 50 (unspent), total weight is 1350 now + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 50 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 50), ..Default::default() }; + + // Actual weight is 25 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 25)), + pays_fee: Default::default(), + }; + + // Adds 50 + 150 (len) weight, total weight is 1200 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN, 0) + .unwrap(); + assert_eq!(pre, Some(100)); + + // Adds additional 150 weight recorded + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + // `CheckWeight` gets called after `StorageWeightReclaim` this time. + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn storage_size_reported_correctly() { + let mut test_ext = setup_test_externalities(&[1000]); + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), Some(1000)); + }); + + let mut test_ext = new_test_ext(); + + let test_recorder = TestRecorder::new(&[0]); + + test_ext.register_extension(ProofSizeExt::new(test_recorder)); + + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), Some(0)); + }); +} + +#[test] +fn storage_size_disabled_reported_correctly() { + let mut test_ext = setup_test_externalities(&[PROOF_RECORDING_DISABLED as usize]); + + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), None); + }); +} + +#[test] +fn test_reclaim_helper() { + let mut test_ext = setup_test_externalities(&[1000, 1300, 1800]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 2000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + remaining_weight_meter.consume(Weight::from_parts(0, 500)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 200))); + + remaining_weight_meter.consume(Weight::from_parts(0, 800)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + assert_eq!(reclaimed, Some(Weight::from_parts(0, 300))); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1200)); + }); +} + +#[test] +fn test_reclaim_helper_does_not_reclaim_negative() { + // Benchmarked weight does not change at all + let mut test_ext = setup_test_externalities(&[1000, 1300]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1000)); + }); + + // Benchmarked weight increases less than storage proof consumes + let mut test_ext = setup_test_externalities(&[1000, 1300]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + remaining_weight_meter.consume(Weight::from_parts(0, 0)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + }); +} + +/// Just here for doc purposes +fn get_benched_weight() -> Weight { + Weight::from_parts(0, 5) +} + +/// Just here for doc purposes +fn do_work() {} + +#[docify::export_content(simple_reclaimer_example)] +fn reclaim_with_weight_meter() { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(10, 10)); + + let benched_weight = get_benched_weight(); + + // It is important to instantiate the `StorageWeightReclaimer` before we consume the weight + // for a piece of work from the weight meter. + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + + if remaining_weight_meter.try_consume(benched_weight).is_ok() { + // Perform some work that takes has `benched_weight` storage weight. + do_work(); + + // Reclaimer will detect that we only consumed 2 bytes, so 3 bytes are reclaimed. + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + // We reclaimed 3 bytes of storage size! + assert_eq!(reclaimed, Some(Weight::from_parts(0, 3))); + assert_eq!(get_storage_weight().total().proof_size(), 10); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(10, 8)); + } +} + +#[test] +fn test_reclaim_helper_works_with_meter() { + // The node will report 12 - 10 = 2 consumed storage size between the calls. + let mut test_ext = setup_test_externalities(&[10, 12]); + + test_ext.execute_with(|| { + // Initial storage size is 10. + set_current_storage_weight(10); + reclaim_with_weight_meter(); + }); +} diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index fbbaab73ce76..33023816c718 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -53,6 +53,7 @@ runtime-benchmarks = [ "cumulus-test-service/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "sc-service/runtime-benchmarks", diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index f26413e441e7..863a8fa93f6f 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -25,7 +25,7 @@ pub use polkadot_parachain_primitives::primitives::{ BlockData, HeadData, ValidationParams, ValidationResult, }; use runtime::{ - Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload, + Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedPayload, TxExtension, UncheckedExtrinsic, VERSION, }; use sc_consensus_aura::standalone::{seal, slot_author}; @@ -39,7 +39,7 @@ use sp_consensus_aura::{AuraApi, Slot}; use sp_core::Pair; use sp_io::TestExternalities; use sp_keystore::testing::MemoryKeystore; -use sp_runtime::{generic::Era, traits::Header, BuildStorage, SaturatedConversion}; +use sp_runtime::{generic::Era, traits::Header, BuildStorage, MultiAddress, SaturatedConversion}; use std::sync::Arc; pub use substrate_test_client::*; @@ -117,7 +117,7 @@ impl DefaultTestClientBuilderExt for TestClientBuilder { /// Create an unsigned extrinsic from a runtime call. pub fn generate_unsigned(function: impl Into) -> UncheckedExtrinsic { - UncheckedExtrinsic::new_unsigned(function.into()) + UncheckedExtrinsic::new_bare(function.into()) } /// Create a signed extrinsic from a runtime call and sign @@ -135,7 +135,7 @@ pub fn generate_extrinsic_with_pair( let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), @@ -144,22 +144,23 @@ pub fn generate_extrinsic_with_pair( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), - ); + ) + .into(); let function = function.into(); let raw_payload = SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ((), VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| origin.sign(e)); UncheckedExtrinsic::new_signed( function, - origin.public().into(), + MultiAddress::Id(origin.public().into()), Signature::Sr25519(signature), - extra, + tx_ext, ) } @@ -180,7 +181,7 @@ pub fn transfer( value: Balance, ) -> UncheckedExtrinsic { let function = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { - dest: dest.public().into(), + dest: MultiAddress::Id(dest.public().into()), value, }); diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 54b83e2dfeda..8117e6e69709 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -11,6 +11,7 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } +serde_json = { workspace = true } # Substrate frame-executive = { workspace = true } @@ -38,6 +39,7 @@ 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-parachain-system = { workspace = true } @@ -76,6 +78,7 @@ std = [ "pallet-transaction-payment/std", "parachain-info/std", "scale-info/std", + "serde_json/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -83,6 +86,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", diff --git a/cumulus/test/runtime/src/genesis_config_presets.rs b/cumulus/test/runtime/src/genesis_config_presets.rs new file mode 100644 index 000000000000..84ba71ae795f --- /dev/null +++ b/cumulus/test/runtime/src/genesis_config_presets.rs @@ -0,0 +1,72 @@ +// 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 super::{ + AccountId, AuraConfig, AuraId, BalancesConfig, ParachainInfoConfig, RuntimeGenesisConfig, + SudoConfig, +}; +use alloc::{vec, vec::Vec}; + +use cumulus_primitives_core::ParaId; +use frame_support::build_struct_json_patch; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; + +fn cumulus_test_runtime( + invulnerables: Vec, + endowed_accounts: Vec, + id: ParaId, +) -> serde_json::Value { + build_struct_json_patch!(RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.public().into()) }, + parachain_info: ParachainInfoConfig { parachain_id: id }, + aura: AuraConfig { authorities: invulnerables }, + }) +} + +fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value { + let endowed = Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect::>(); + + let invulnerables = + Sr25519Keyring::invulnerable().map(|x| x.public().into()).collect::>(); + cumulus_test_runtime(invulnerables, endowed, self_para_id) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + vec![ + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &PresetId) -> Option> { + 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, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 92a6ab73a2eb..b1649c410581 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -32,6 +32,7 @@ pub mod elastic_scaling { include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling.rs")); } +mod genesis_config_presets; mod test_pallet; extern crate alloc; @@ -44,10 +45,10 @@ use sp_core::{ConstBool, ConstU32, ConstU64, OpaqueMetadata}; use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector}; use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Verify}, + generic, impl_opaque_keys, + traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, Verify}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, MultiAddress, MultiSignature, }; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -125,8 +126,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, @@ -139,8 +140,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, @@ -208,8 +209,6 @@ parameter_types! { impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = IdentityLookup; /// The index type for storing how many extrinsics an account has signed. type Nonce = Nonce; /// The type for hashing blocks and tries. @@ -279,6 +278,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_sudo::Config for Runtime { @@ -362,7 +362,7 @@ pub type AccountId = <::Signer as IdentifyAccount>::Account pub type NodeBlock = generic::Block; /// The address format for describing accounts. -pub type Address = AccountId; +pub type Address = MultiAddress; /// Block header type as expected by this runtime. pub type Header = generic::Header; /// Block type as expected by this runtime. @@ -371,8 +371,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckGenesis, @@ -384,7 +384,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -395,7 +395,7 @@ pub type Executive = frame_executive::Executive< TestOnRuntimeUpgrade, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; pub struct TestOnRuntimeUpgrade; @@ -543,11 +543,11 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() } } } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index a1b70c523952..86a8c48bb54f 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -49,6 +49,7 @@ sp-core = { 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 } @@ -110,6 +111,7 @@ runtime-benchmarks = [ "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/cumulus/test/service/benches/transaction_throughput.rs b/cumulus/test/service/benches/transaction_throughput.rs index 011eb4c7d50e..bba624e36ad1 100644 --- a/cumulus/test/service/benches/transaction_throughput.rs +++ b/cumulus/test/service/benches/transaction_throughput.rs @@ -54,7 +54,7 @@ fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec SudoCall::sudo { call: Box::new( BalancesCall::force_set_balance { - who: AccountId::from(a.public()), + who: AccountId::from(a.public()).into(), new_free: 0, } .into(), @@ -69,7 +69,7 @@ fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec SudoCall::sudo { call: Box::new( BalancesCall::force_set_balance { - who: AccountId::from(a.public()), + who: AccountId::from(a.public()).into(), new_free: 1_000_000_000_000 * ExistentialDeposit::get(), } .into(), @@ -96,7 +96,7 @@ fn create_benchmark_extrinsics( construct_extrinsic( client, BalancesCall::transfer_allow_death { - dest: Bob.to_account_id(), + dest: Bob.to_account_id().into(), value: ExistentialDeposit::get(), }, account.clone(), diff --git a/cumulus/test/service/benches/validate_block.rs b/cumulus/test/service/benches/validate_block.rs index 34b09d99ce98..ca20de338f3c 100644 --- a/cumulus/test/service/benches/validate_block.rs +++ b/cumulus/test/service/benches/validate_block.rs @@ -60,7 +60,10 @@ fn create_extrinsics( let extrinsic: UncheckedExtrinsic = generate_extrinsic_with_pair( client, src.clone(), - BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()), value: 10000 }, + BalancesCall::transfer_keep_alive { + dest: AccountId::from(dst.public()).into(), + value: 10000, + }, None, ); diff --git a/cumulus/test/service/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 67ffbdd1d212..49ba1b230cc3 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -41,7 +41,7 @@ use sp_core::{sr25519, Pair}; use sp_keyring::Sr25519Keyring::Alice; use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, - AccountId32, FixedU64, OpaqueExtrinsic, + AccountId32, FixedU64, MultiAddress, OpaqueExtrinsic, }; /// Accounts to use for transfer transactions. Enough for 5000 transactions. @@ -68,12 +68,11 @@ pub fn extrinsic_set_time(client: &TestClient) -> OpaqueExtrinsic { let best_number = client.usage_info().chain.best_number; let timestamp = best_number as u64 * cumulus_test_runtime::MinimumPeriod::get(); - cumulus_test_runtime::UncheckedExtrinsic { - signature: None, - function: cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { + cumulus_test_runtime::UncheckedExtrinsic::new_bare( + cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: timestamp, }), - } + ) .into() } @@ -101,12 +100,11 @@ pub fn extrinsic_set_validation_data( horizontal_messages: Default::default(), }; - cumulus_test_runtime::UncheckedExtrinsic { - signature: None, - function: cumulus_test_runtime::RuntimeCall::ParachainSystem( + cumulus_test_runtime::UncheckedExtrinsic::new_bare( + cumulus_test_runtime::RuntimeCall::ParachainSystem( cumulus_pallet_parachain_system::Call::set_validation_data { data }, ), - } + ) .into() } @@ -153,7 +151,10 @@ pub fn create_benchmarking_transfer_extrinsics( for (src, dst) in src_accounts.iter().zip(dst_accounts.iter()) { let extrinsic: UncheckedExtrinsic = construct_extrinsic( client, - BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()), value: 10000 }, + BalancesCall::transfer_keep_alive { + dest: MultiAddress::Id(AccountId::from(dst.public())), + value: 10000, + }, src.clone(), Some(0), ); diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index ae71028ad486..3d4e4dca5f8d 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -16,25 +16,17 @@ #![allow(missing_docs)] +use cumulus_client_service::ParachainHostFunctions; use cumulus_primitives_core::ParaId; -use cumulus_test_runtime::{AccountId, Signature}; -use parachains_common::AuraId; -use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; +use cumulus_test_runtime::AccountId; +use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, GenesisConfigBuilderRuntimeCaller}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; -use sp_core::{sr25519, Pair, Public}; -use sp_runtime::traits::{IdentifyAccount, Verify}; +use serde_json::json; /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - /// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] #[serde(deny_unknown_fields)] @@ -50,16 +42,6 @@ impl Extensions { } } -type AccountPublic = ::Signer; - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - /// Get the chain spec for a specific parachain ID. /// The given accounts are initialized with funds in addition /// to the default known accounts. @@ -68,17 +50,51 @@ pub fn get_chain_spec_with_extra_endowed( extra_endowed_accounts: Vec, code: &[u8], ) -> ChainSpec { + let runtime_caller = GenesisConfigBuilderRuntimeCaller::::new(code); + let mut development_preset = runtime_caller + .get_named_preset(Some(&sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET.to_string())) + .expect("development preset is available on test runtime; qed"); + + // Extract existing balances + let existing_balances = development_preset + .get("balances") + .and_then(|b| b.get("balances")) + .and_then(|b| b.as_array()) + .cloned() + .unwrap_or_default(); + + // Create new balances by combining existing and extra accounts + let mut all_balances = existing_balances; + all_balances.extend(extra_endowed_accounts.into_iter().map(|a| json!([a, 1u64 << 60]))); + + let mut patch_json = json!({ + "balances": { + "balances": all_balances, + } + }); + + if let Some(id) = id { + // Merge parachain ID if given, otherwise use the one from the preset. + sc_chain_spec::json_merge( + &mut patch_json, + json!({ + "parachainInfo": { + "parachainId": id, + }, + }), + ); + }; + + sc_chain_spec::json_merge(&mut development_preset, patch_json.into()); + ChainSpec::builder( code, Extensions { para_id: id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()).into() }, ) .with_name("Local Testnet") - .with_id("local_testnet") + .with_id(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_chain_type(ChainType::Local) - .with_genesis_config_patch(testnet_genesis_with_default_endowed( - extra_endowed_accounts.clone(), - id, - )) + .with_genesis_config_patch(development_preset) .build() } @@ -100,66 +116,3 @@ pub fn get_elastic_scaling_chain_spec(id: Option) -> ChainSpec { .expect("WASM binary was not built, please build it!"), ) } - -/// Local testnet genesis for testing. -pub fn testnet_genesis_with_default_endowed( - mut extra_endowed_accounts: Vec, - self_para_id: Option, -) -> serde_json::Value { - let mut endowed = vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ]; - endowed.append(&mut extra_endowed_accounts); - let invulnerables = vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - get_collator_keys_from_seed::("Charlie"), - get_collator_keys_from_seed::("Dave"), - get_collator_keys_from_seed::("Eve"), - get_collator_keys_from_seed::("Ferdie"), - ]; - testnet_genesis( - get_account_id_from_seed::("Alice"), - invulnerables, - endowed, - self_para_id, - ) -} - -/// Generate collator keys from seed. -/// -/// This function's return type must always match the session keys of the chain in tuple format. -pub fn get_collator_keys_from_seed(seed: &str) -> ::Public { - get_from_seed::(seed) -} - -/// Creates a local testnet genesis with endowed accounts. -pub fn testnet_genesis( - root_key: AccountId, - invulnerables: Vec, - endowed_accounts: Vec, - self_para_id: Option, -) -> serde_json::Value { - let self_para_id = self_para_id.unwrap_or(cumulus_test_runtime::PARACHAIN_ID.into()); - serde_json::json!({ - "balances": cumulus_test_runtime::BalancesConfig { - balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), - }, - "sudo": cumulus_test_runtime::SudoConfig { key: Some(root_key) }, - "parachainInfo": { - "parachainId": self_para_id, - }, - "aura": cumulus_test_runtime::AuraConfig { authorities: invulnerables } - }) -} diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 9f93572e9cea..9234442d399c 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -90,7 +90,7 @@ use sp_arithmetic::traits::SaturatedConversion; use sp_blockchain::HeaderBackend; use sp_core::Pair; use sp_keyring::Sr25519Keyring; -use sp_runtime::{codec::Encode, generic}; +use sp_runtime::{codec::Encode, generic, MultiAddress}; use sp_state_machine::BasicExternalities; use std::sync::Arc; use substrate_test_client::{ @@ -134,7 +134,7 @@ pub type Backend = TFullBackend; pub type ParachainBlockImport = TParachainBlockImport, Backend>; /// Transaction pool type used by the test service -pub type TransactionPool = Arc>; +pub type TransactionPool = Arc>; /// Recovery handle that fails regularly to simulate unavailable povs. pub struct FailingRecoveryHandle { @@ -183,7 +183,7 @@ pub type Service = PartialComponents< Backend, (), sc_consensus::import_queue::BasicQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ParachainBlockImport, >; @@ -219,12 +219,15 @@ pub fn new_partial( let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let slot_duration = sc_consensus_aura::slot_duration(&*client)?; @@ -364,7 +367,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, @@ -539,8 +542,6 @@ where } } - start_network.start_network(); - Ok((task_manager, client, network, rpc_handlers, transaction_pool, backend)) } @@ -966,7 +967,7 @@ pub fn construct_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), @@ -978,18 +979,19 @@ pub fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), - ); + ) + .into(); let raw_payload = runtime::SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ((), runtime::VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| caller.sign(e)); runtime::UncheckedExtrinsic::new_signed( function, - caller.public().into(), + MultiAddress::Id(caller.public().into()), runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index bb2945dc267d..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, @@ -49,7 +52,9 @@ pub use frame_system::{ pub use pallet_balances::AccountData; pub use pallet_message_queue; pub use sp_arithmetic::traits::Bounded; -pub use sp_core::{parameter_types, sr25519, storage::Storage, Pair}; +pub use sp_core::{ + crypto::get_public_from_string_or_panic, parameter_types, sr25519, storage::Storage, Pair, +}; pub use sp_crypto_hashing::blake2_256; pub use sp_io::TestExternalities; pub use sp_runtime::BoundedSlice; @@ -219,14 +224,14 @@ 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; type OriginCaller; fn account_id_of(seed: &str) -> AccountId { - helpers::get_account_id_from_seed::(seed) + get_public_from_string_or_panic::(seed).into() } fn account_data_of(account: AccountIdOf) -> AccountData; @@ -1219,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>>(); @@ -1227,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); } @@ -1528,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, @@ -1542,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 { @@ -1557,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(), } @@ -1571,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()); @@ -1608,17 +1629,4 @@ pub mod helpers { ref_time_within && proof_size_within } - - /// Helper function to generate an account ID from seed. - pub fn get_account_id_from_seed(seed: &str) -> AccountId - where - sp_runtime::MultiSigner: - From<<::Pair as sp_core::Pair>::Public>, - { - use sp_runtime::traits::IdentifyAccount; - let pubkey = TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public(); - sp_runtime::MultiSigner::from(pubkey).into_account() - } } diff --git a/cumulus/zombienet/examples/small_network.toml b/cumulus/zombienet/examples/small_network.toml index ab7265712308..64765566471a 100644 --- a/cumulus/zombienet/examples/small_network.toml +++ b/cumulus/zombienet/examples/small_network.toml @@ -3,23 +3,23 @@ default_image = "parity/polkadot:latest" default_command = "polkadot" chain = "rococo-local" - [[relaychain.nodes]] - name = "alice" - validator = true +[[relaychain.nodes]] +name = "alice" +validator = true - [[relaychain.nodes]] - name = "bob" - validator = true +[[relaychain.nodes]] +name = "bob" +validator = true [[parachains]] id = 2000 cumulus_based = true chain = "asset-hub-rococo-local" - # run charlie as parachain collator - [[parachains.collators]] - name = "charlie" - validator = true - image = "parity/polkadot-parachain:latest" - command = "polkadot-parachain" - args = ["--force-authoring"] +# run charlie as parachain collator +[[parachains.collators]] +name = "charlie" +validator = true +image = "parity/polkadot-parachain:latest" +command = "polkadot-parachain" +args = ["--force-authoring"] diff --git a/cumulus/zombienet/tests/0008-main.js b/cumulus/zombienet/tests/0008-main.js new file mode 100644 index 000000000000..31c01324a77e --- /dev/null +++ b/cumulus/zombienet/tests/0008-main.js @@ -0,0 +1,18 @@ +// Allows to manually submit extrinsic to collator. +// Usage: +// zombienet-linux -p native spwan 0008-parachain-extrinsic-gets-finalized.toml +// node 0008-main.js + +global.zombie = null + +const fs = require('fs'); +const test = require('./0008-transaction_gets_finalized.js'); + +if (process.argv.length == 2) { + console.error('Path to zombie.json (generated by zombienet-linux spawn command shall be given)!'); + process.exit(1); +} + +let networkInfo = JSON.parse(fs.readFileSync(process.argv[2])); + +test.run("charlie", networkInfo).then(process.exit) diff --git a/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.toml b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.toml new file mode 100644 index 000000000000..a295d3960bfe --- /dev/null +++ b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.toml @@ -0,0 +1,25 @@ +[relaychain] +default_image = "{{RELAY_IMAGE}}" +default_command = "polkadot" +chain = "rococo-local" + + [[relaychain.nodes]] + name = "alice" + validator = true + + [[relaychain.nodes]] + name = "bob" + validator = true + +[[parachains]] +id = 2000 +cumulus_based = true +chain = "asset-hub-rococo-local" + + # run charlie as parachain collator + [[parachains.collators]] + name = "charlie" + validator = true + image = "{{POLKADOT_PARACHAIN_IMAGE}}" + command = "polkadot-parachain" + args = ["--force-authoring", "-ltxpool=trace", "--pool-type=fork-aware"] diff --git a/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.zndsl b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.zndsl new file mode 100644 index 000000000000..5aab1bd923a5 --- /dev/null +++ b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.zndsl @@ -0,0 +1,20 @@ +Description: Block building +Network: ./0008-parachain_extrinsic_gets_finalized.toml +Creds: config + +alice: reports node_roles is 4 +bob: reports node_roles is 4 +charlie: reports node_roles is 4 + +alice: reports peers count is at least 1 +bob: reports peers count is at least 1 + +alice: reports block height is at least 5 within 60 seconds +bob: reports block height is at least 5 within 60 seconds +charlie: reports block height is at least 2 within 120 seconds + +alice: count of log lines containing "error" is 0 within 2 seconds +bob: count of log lines containing "error" is 0 within 2 seconds +charlie: count of log lines containing "error" is 0 within 2 seconds + +charlie: js-script ./0008-transaction_gets_finalized.js within 600 seconds diff --git a/cumulus/zombienet/tests/0008-transaction_gets_finalized.js b/cumulus/zombienet/tests/0008-transaction_gets_finalized.js new file mode 100644 index 000000000000..3031c45e3a4b --- /dev/null +++ b/cumulus/zombienet/tests/0008-transaction_gets_finalized.js @@ -0,0 +1,69 @@ +//based on: https://polkadot.js.org/docs/api/examples/promise/transfer-events + +const assert = require("assert"); + +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + // Create the API and wait until ready + var api = null; + var keyring = null; + if (zombie == null) { + const testKeyring = require('@polkadot/keyring/testing'); + const { WsProvider, ApiPromise } = require('@polkadot/api'); + const provider = new WsProvider(wsUri); + api = await ApiPromise.create({provider}); + // Construct the keyring after the API (crypto has an async init) + keyring = testKeyring.createTestKeyring({ type: "sr25519" }); + } else { + keyring = new zombie.Keyring({ type: "sr25519" }); + api = await zombie.connect(wsUri, userDefinedTypes); + } + + + // Add Alice to our keyring with a hard-derivation path (empty phrase, so uses dev) + const alice = keyring.addFromUri('//Alice'); + + // Create an extrinsic: + const extrinsic = api.tx.system.remark("xxx"); + + let extrinsic_success_event = false; + try { + await new Promise( async (resolve, reject) => { + const unsubscribe = await extrinsic + .signAndSend(alice, { nonce: -1 }, ({ events = [], status }) => { + console.log('Extrinsic status:', status.type); + + if (status.isInBlock) { + console.log('Included at block hash', status.asInBlock.toHex()); + console.log('Events:'); + + events.forEach(({ event: { data, method, section }, phase }) => { + console.log('\t', phase.toString(), `: ${section}.${method}`, data.toString()); + + if (section=="system" && method =="ExtrinsicSuccess") { + extrinsic_success_event = true; + } + }); + } else if (status.isFinalized) { + console.log('Finalized block hash', status.asFinalized.toHex()); + unsubscribe(); + if (extrinsic_success_event) { + resolve(); + } else { + reject("ExtrinsicSuccess has not been seen"); + } + } else if (status.isError) { + unsubscribe(); + reject("Extrinsic status.isError"); + } + + }); + }); + } catch (error) { + assert.fail("Transfer promise failed, error: " + error); + } + + assert.ok("test passed"); +} + +module.exports = { run } diff --git a/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml b/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml index b695f8aa9376..1cf0775a2e17 100644 --- a/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml +++ b/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml @@ -1,6 +1,14 @@ [settings] timeout = 1000 +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + +[parachain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + [relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] max_candidate_depth = 6 allowed_ancestry_len = 3 @@ -23,7 +31,11 @@ command = "polkadot" [[relaychain.node_groups]] name = "validator" - args = ["-lruntime=debug,parachain=trace", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] + args = [ + "-lruntime=debug,parachain=trace", + "--reserved-only", + "--reserved-nodes {{'alice'|zombie('multiAddress')}}" + ] count = 8 # Slot based authoring with 3 cores and 2s slot duration @@ -32,17 +44,29 @@ id = 2100 chain = "elastic-scaling" add_to_genesis = false - # Slot based authoring with 3 cores and 2s slot duration + # run 'recovery-target' as a parachain full node [[parachains.collators]] - name = "collator-elastic" + name = "recovery-target" + validator = false # full node image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["--disable-block-announcements", "-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", "--force-authoring", "--experimental-use-slot-based"] + args = [ + "-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", + "--disable-block-announcements", + "--in-peers 0", + "--out-peers 0", + "--", + "--reserved-only", + "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] - # run 'recovery-target' as a parachain full node + # Slot based authoring with 3 cores and 2s slot duration [[parachains.collators]] - name = "recovery-target" - validator = false # full node + name = "collator-elastic" image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'collator-elastic'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0", "--", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] + args = [ + "-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", + "--disable-block-announcements", + "--force-authoring", + "--experimental-use-slot-based" + ] diff --git a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile index 2198da13a4b7..b1f4bffc772a 100644 --- a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile +++ b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile @@ -1,7 +1,7 @@ # this image is built on top of existing Zombienet image ARG ZOMBIENET_IMAGE # this image uses substrate-relay image built elsewhere -ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.6.10 +ARG SUBSTRATE_RELAY_IMAGE=docker.io/paritytech/substrate-relay:v1.7.0 # metadata ARG VCS_REF diff --git a/docker/scripts/polkadot-omni-node/build-injected.sh b/docker/scripts/polkadot-omni-node/build-injected.sh new file mode 100755 index 000000000000..a39621bac3d6 --- /dev/null +++ b/docker/scripts/polkadot-omni-node/build-injected.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Sample call: +# $0 /path/to/folder_with_binary +# This script replace the former dedicated Dockerfile +# and shows how to use the generic binary_injected.dockerfile + +PROJECT_ROOT=`git rev-parse --show-toplevel` + +export BINARY=polkadot-omni-node +export ARTIFACTS_FOLDER=$1 +# export TAGS=... + +$PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docs/contributor/commands-readme.md b/docs/contributor/commands-readme.md index 861c3ac784d5..52c554cc7098 100644 --- a/docs/contributor/commands-readme.md +++ b/docs/contributor/commands-readme.md @@ -24,11 +24,6 @@ By default, the Start and End/Failure of the command will be commented with the If you want to avoid, use this flag. Go to [Action Tab](https://github.com/paritytech/polkadot-sdk/actions/workflows/cmd.yml) to see the pipeline status. -2.`--continue-on-fail` to continue running the command even if something inside a command -(like specific pallet weight generation) are failed. -Basically avoids interruption in the middle with `exit 1` -The pipeline logs will include what is failed (like which runtimes/pallets), then you can re-run them separately or not. - 3.`--clean` to clean up all yours and bot's comments in PR relevant to `/cmd` commands. If you run too many commands, or they keep failing, and you're rerunning them again, it's handy to add this flag to keep a PR clean. @@ -44,4 +39,5 @@ the default branch. The regex in cmd.yml is: `^(\/cmd )([-\/\s\w.=:]+)$` accepts only alphanumeric, space, "-", "/", "=", ":", "." chars. `/cmd bench --runtime bridge-hub-westend --pallet=pallet_name` +`/cmd prdoc --audience runtime_dev runtime_user --bump patch --force` `/cmd update-ui --image=docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v202407161507 --clean` diff --git a/docs/contributor/weight-generation.md b/docs/contributor/weight-generation.md index ebfdca59cae5..a22a55404a44 100644 --- a/docs/contributor/weight-generation.md +++ b/docs/contributor/weight-generation.md @@ -3,7 +3,7 @@ To generate weights for a runtime. Weights generation is using self-hosted runner which is provided by Parity CI, the rest commands are using standard GitHub runners on `ubuntu-latest` or `ubuntu-20.04`. -Self-hosted runner for benchmarks (arc-runners-Polkadot-sdk-benchmark) is configured to meet requirements of reference +Self-hosted runner for benchmarks (`parity-weights`) is configured to meet requirements of reference hardware for running validators https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware @@ -19,51 +19,53 @@ In a PR run the actions through comment: To regenerate all weights (however it will take long, so don't do it unless you really need it), run the following command: + ```sh /cmd bench ``` To generate weights for all pallets in a particular runtime(s), run the following command: + ```sh /cmd bench --runtime kusama polkadot ``` For Substrate pallets (supports sub-modules too): + ```sh /cmd bench --runtime dev --pallet pallet_asset_conversion_ops ``` > **📝 Note**: The action is not being run right-away, it will be queued and run in the next available runner. -So might be quick, but might also take up to 10 mins (That's in control of Github). -Once the action is run, you'll see reaction 👀 on original comment, and if you didn't pass `--quiet` - -it will also send a link to a pipeline when started, and link to whole workflow when finished. +> So might be quick, but might also take up to 10 mins (That's in control of Github). +> Once the action is run, you'll see reaction 👀 on original comment, and if you didn't pass `--quiet` - +> it will also send a link to a pipeline when started, and link to whole workflow when finished. +> +> **📝 Note**: It will try keep benchmarking even if some pallets failed, with the result of failed/successful pallets. +> +> If you want to fail fast on first failed benchmark, add `--fail-fast` flag to the command. --- -> **💡Hint #1** : if you run all runtimes or all pallets, it might be that some pallet in the middle is failed -to generate weights, thus it stops (fails) the whole pipeline. -> If you want, you can make it to continue running, even if some pallets are failed, add `--continue-on-fail` -flag to the command. The report will include which runtimes/pallets have failed, then you can re-run -them separately after all is done. - This way it runs all possible runtimes for the specified pallets, if it finds them in the runtime + ```sh /cmd bench --pallet pallet_balances pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible ``` If you want to run all specific pallet(s) for specific runtime(s), you can do it like this: + ```sh /cmd bench --runtime bridge-hub-polkadot --pallet pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible ``` - -> **💡Hint #2** : Sometimes when you run too many commands, or they keep failing and you're rerunning them again, -it's handy to add `--clean` flag to the command. This will clean up all yours and bot's comments in PR relevant to -/cmd commands. +> **💡Hint #1** : Sometimes when you run too many commands, or they keep failing and you're rerunning them again, +> it's handy to add `--clean` flag to the command. This will clean up all yours and bot's comments in PR relevant to +> /cmd commands. ```sh -/cmd bench --runtime kusama polkadot --pallet=pallet_balances --clean --continue-on-fail +/cmd bench --runtime kusama polkadot --pallet=pallet_balances --clean ``` -> **💡Hint #3** : If you have questions or need help, feel free to tag @paritytech/opstooling (in github comments) -or ping in [matrix](https://matrix.to/#/#command-bot:parity.io) channel. +> **💡Hint #2** : If you have questions or need help, feel free to tag @paritytech/opstooling (in github comments) +> or ping in [matrix](https://matrix.to/#/#command-bot:parity.io) channel. diff --git a/docs/mermaid/IA.mmd b/docs/mermaid/IA.mmd index 37417497e1f8..dcf9806dcb62 100644 --- a/docs/mermaid/IA.mmd +++ b/docs/mermaid/IA.mmd @@ -1,13 +1,12 @@ flowchart parity[paritytech.github.io] --> devhub[polkadot_sdk_docs] - polkadot_network[polkadot.network] --> devhub[polkadot_sdk_docs] devhub --> polkadot_sdk devhub --> reference_docs devhub --> guides + devhub --> external_resources polkadot_sdk --> substrate polkadot_sdk --> frame - polkadot_sdk --> cumulus - polkadot_sdk --> polkadot[polkadot node] polkadot_sdk --> xcm + polkadot_sdk --> templates diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index adc1c1a8efbc..0c39367eeed3 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -29,6 +29,7 @@ pallet-example-offchain-worker = { workspace = true, default-features = true } # How we build docs in rust-docs simple-mermaid = "0.1.1" docify = { workspace = true } +serde_json = { workspace = true } # 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 } @@ -39,6 +40,8 @@ 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-metadata-hash-extension = { workspace = true, default-features = true } log = { workspace = true, default-features = true } @@ -69,6 +72,9 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true, default-feature cumulus-client-service = { workspace = true, default-features = true } cumulus-primitives-storage-weight-reclaim = { 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 } @@ -91,6 +97,7 @@ pallet-scheduler = { 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 } # Primitives sp-io = { workspace = true, default-features = true } @@ -105,6 +112,7 @@ sp-arithmetic = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } sp-offchain = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } +sp-weights = { workspace = true, default-features = true } # XCM @@ -116,9 +124,18 @@ xcm-simulator = { workspace = true } pallet-xcm = { workspace = true } # runtime guides -chain-spec-guide-runtime = { workspace = true } + +chain-spec-guide-runtime = { workspace = true, default-features = true } # Templates -minimal-template-runtime = { workspace = true } -solochain-template-runtime = { workspace = true } -parachain-template-runtime = { workspace = true } +minimal-template-runtime = { workspace = true, default-features = true } +solochain-template-runtime = { workspace = true, default-features = true } +parachain-template-runtime = { workspace = true, default-features = true } + +# local packages +first-runtime = { workspace = true, default-features = true } +first-pallet = { workspace = true, default-features = true } + +[dev-dependencies] +assert_cmd = "2.0.14" +rand = "0.8" diff --git a/docs/sdk/assets/theme.css b/docs/sdk/assets/theme.css index 1f47a8ef5b0c..f9aa4760275e 100644 --- a/docs/sdk/assets/theme.css +++ b/docs/sdk/assets/theme.css @@ -6,6 +6,27 @@ --polkadot-purple: #552BBF; } +/* Light theme */ +html[data-theme="light"] { + --quote-background: #f9f9f9; + --quote-border: #ccc; + --quote-text: #333; +} + +/* Dark theme */ +html[data-theme="dark"] { + --quote-background: #333; + --quote-border: #555; + --quote-text: #f9f9f9; +} + +/* Ayu theme */ +html[data-theme="ayu"] { + --quote-background: #272822; + --quote-border: #383830; + --quote-text: #f8f8f2; +} + body.sdk-docs { nav.sidebar>div.sidebar-crate>a>img { width: 190px; @@ -20,3 +41,17 @@ body.sdk-docs { html[data-theme="light"] .sidebar-crate > .logo-container > img { content: url("https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/images/Polkadot_Logo_Horizontal_Pink_Black.png"); } + +/* Custom styles for blockquotes */ +blockquote { + background-color: var(--quote-background); + border-left: 5px solid var(--quote-border); + color: var(--quote-text); + margin: 1em 0; + padding: 1em 1.5em; + /* font-style: italic; */ +} + +blockquote p { + margin: 0; +} diff --git a/docs/sdk/packages/guides/first-pallet/Cargo.toml b/docs/sdk/packages/guides/first-pallet/Cargo.toml new file mode 100644 index 000000000000..dad5b8863494 --- /dev/null +++ b/docs/sdk/packages/guides/first-pallet/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "polkadot-sdk-docs-first-pallet" +description = "A simple pallet created for the polkadot-sdk-docs guides" +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true +publish = false + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { workspace = true } +scale-info = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } +docify = { workspace = true } + +[features] +default = ["std"] +std = ["codec/std", "frame/std", "scale-info/std"] diff --git a/docs/sdk/packages/guides/first-pallet/src/lib.rs b/docs/sdk/packages/guides/first-pallet/src/lib.rs new file mode 100644 index 000000000000..168b7ca44aba --- /dev/null +++ b/docs/sdk/packages/guides/first-pallet/src/lib.rs @@ -0,0 +1,480 @@ +// 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. + +//! Pallets used in the `your_first_pallet` guide. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod shell_pallet { + use frame::prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); +} + +#[frame::pallet(dev_mode)] +pub mod pallet { + use frame::prelude::*; + + #[docify::export] + pub type Balance = u128; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export] + /// Single storage item, of type `Balance`. + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + /// A mapping from `T::AccountId` to `Balance` + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[docify::export(impl_pallet)] + #[pallet::call] + impl Pallet { + /// An unsafe mint that can be called by anyone. Not a great idea. + pub fn mint_unsafe( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + // ensure that this is a signed account, but we don't really check `_anyone`. + let _anyone = ensure_signed(origin)?; + + // update the balances map. Notice how all `` remains as ``. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + // update total issuance. + TotalIssuance::::mutate(|t| *t = Some(t.unwrap_or(0) + amount)); + + Ok(()) + } + + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + if sender_balance < amount { + return Err("InsufficientBalance".into()) + } + let remainder = sender_balance - amount; + + // update sender and dest balances. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, remainder); + + Ok(()) + } + } + + #[allow(unused)] + impl Pallet { + #[docify::export] + pub fn transfer_better( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + ensure!(sender_balance >= amount, "InsufficientBalance"); + let remainder = sender_balance - amount; + + // .. snip + Ok(()) + } + + #[docify::export] + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer_better_checked( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + let remainder = sender_balance.checked_sub(amount).ok_or("InsufficientBalance")?; + + // .. snip + Ok(()) + } + } + + #[cfg(any(test, doc))] + pub(crate) mod tests { + use crate::pallet::*; + + #[docify::export(testing_prelude)] + use frame::testing_prelude::*; + + pub(crate) const ALICE: u64 = 1; + pub(crate) const BOB: u64 = 2; + pub(crate) const CHARLIE: u64 = 3; + + #[docify::export] + // This runtime is only used for testing, so it should be somewhere like `#[cfg(test)] mod + // tests { .. }` + mod runtime { + use super::*; + // we need to reference our `mod pallet` as an identifier to pass to + // `construct_runtime`. + // YOU HAVE TO CHANGE THIS LINE BASED ON YOUR TEMPLATE + use crate::pallet as pallet_currency; + + construct_runtime!( + pub enum Runtime { + // ---^^^^^^ This is where `enum Runtime` is defined. + System: frame_system, + Currency: pallet_currency, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + // within pallet we just said `::AccountId`, now we + // finally specified it. + type AccountId = u64; + } + + // our simple pallet has nothing to be configured. + impl pallet_currency::Config for Runtime {} + } + + pub(crate) use runtime::*; + + #[allow(unused)] + #[docify::export] + fn new_test_state_basic() -> TestState { + let mut state = TestState::new_empty(); + let accounts = vec![(ALICE, 100), (BOB, 100)]; + state.execute_with(|| { + for (who, amount) in &accounts { + Balances::::insert(who, amount); + TotalIssuance::::mutate(|b| *b = Some(b.unwrap_or(0) + amount)); + } + }); + + state + } + + #[docify::export] + pub(crate) struct StateBuilder { + balances: Vec<(::AccountId, Balance)>, + } + + #[docify::export(default_state_builder)] + impl Default for StateBuilder { + fn default() -> Self { + Self { balances: vec![(ALICE, 100), (BOB, 100)] } + } + } + + #[docify::export(impl_state_builder_add)] + impl StateBuilder { + fn add_balance( + mut self, + who: ::AccountId, + amount: Balance, + ) -> Self { + self.balances.push((who, amount)); + self + } + } + + #[docify::export(impl_state_builder_build)] + impl StateBuilder { + pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = TestState::new_empty(); + ext.execute_with(|| { + for (who, amount) in &self.balances { + Balances::::insert(who, amount); + TotalIssuance::::mutate(|b| *b = Some(b.unwrap_or(0) + amount)); + } + }); + + ext.execute_with(test); + + // assertions that must always hold + ext.execute_with(|| { + assert_eq!( + Balances::::iter().map(|(_, x)| x).sum::(), + TotalIssuance::::get().unwrap_or_default() + ); + }) + } + } + + #[docify::export] + #[test] + fn first_test() { + TestState::new_empty().execute_with(|| { + // We expect Alice's account to have no funds. + assert_eq!(Balances::::get(&ALICE), None); + assert_eq!(TotalIssuance::::get(), None); + + // mint some funds into Alice's account. + assert_ok!(Pallet::::mint_unsafe( + RuntimeOrigin::signed(ALICE), + ALICE, + 100 + )); + + // re-check the above + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(100)); + }) + } + + #[docify::export] + #[test] + fn state_builder_works() { + StateBuilder::default().build_and_execute(|| { + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(Balances::::get(&BOB), Some(100)); + assert_eq!(Balances::::get(&CHARLIE), None); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + + #[docify::export] + #[test] + fn state_builder_add_balance() { + StateBuilder::default().add_balance(CHARLIE, 42).build_and_execute(|| { + assert_eq!(Balances::::get(&CHARLIE), Some(42)); + assert_eq!(TotalIssuance::::get(), Some(242)); + }) + } + + #[test] + #[should_panic] + fn state_builder_duplicate_genesis_fails() { + StateBuilder::default() + .add_balance(CHARLIE, 42) + .add_balance(CHARLIE, 43) + .build_and_execute(|| { + assert_eq!(Balances::::get(&CHARLIE), None); + assert_eq!(TotalIssuance::::get(), Some(242)); + }) + } + + #[docify::export] + #[test] + fn mint_works() { + StateBuilder::default().build_and_execute(|| { + // given the initial state, when: + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(ALICE), BOB, 100)); + + // then: + assert_eq!(Balances::::get(&BOB), Some(200)); + assert_eq!(TotalIssuance::::get(), Some(300)); + + // given: + assert_ok!(Pallet::::mint_unsafe( + RuntimeOrigin::signed(ALICE), + CHARLIE, + 100 + )); + + // then: + assert_eq!(Balances::::get(&CHARLIE), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(400)); + }); + } + + #[docify::export] + #[test] + fn transfer_works() { + StateBuilder::default().build_and_execute(|| { + // given the initial state, when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(ALICE), BOB, 50)); + + // then: + assert_eq!(Balances::::get(&ALICE), Some(50)); + assert_eq!(Balances::::get(&BOB), Some(150)); + assert_eq!(TotalIssuance::::get(), Some(200)); + + // when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(BOB), ALICE, 50)); + + // then: + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(Balances::::get(&BOB), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + + #[docify::export] + #[test] + fn transfer_from_non_existent_fails() { + StateBuilder::default().build_and_execute(|| { + // given the initial state, when: + assert_err!( + Pallet::::transfer(RuntimeOrigin::signed(CHARLIE), ALICE, 10), + "NonExistentAccount" + ); + + // then nothing has changed. + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(Balances::::get(&BOB), Some(100)); + assert_eq!(Balances::::get(&CHARLIE), None); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + } +} + +#[frame::pallet(dev_mode)] +pub mod pallet_v2 { + use super::pallet::Balance; + use frame::prelude::*; + + #[docify::export(config_v2)] + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type of the runtime. + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + + TryInto>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + #[pallet::error] + pub enum Error { + /// Account does not exist. + NonExistentAccount, + /// Account does not have enough balance. + InsufficientBalance, + } + + #[docify::export] + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A transfer succeeded. + Transferred { from: T::AccountId, to: T::AccountId, amount: Balance }, + } + + #[pallet::call] + impl Pallet { + #[docify::export(transfer_v2)] + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = + Balances::::get(&sender).ok_or(Error::::NonExistentAccount)?; + let remainder = + sender_balance.checked_sub(amount).ok_or(Error::::InsufficientBalance)?; + + Balances::::mutate(&dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, remainder); + + Self::deposit_event(Event::::Transferred { from: sender, to: dest, amount }); + + Ok(()) + } + } + + #[cfg(any(test, doc))] + pub mod tests { + use super::{super::pallet::tests::StateBuilder, *}; + use frame::testing_prelude::*; + const ALICE: u64 = 1; + const BOB: u64 = 2; + + #[docify::export] + pub mod runtime_v2 { + use super::*; + use crate::pallet_v2 as pallet_currency; + + construct_runtime!( + pub enum Runtime { + System: frame_system, + Currency: pallet_currency, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + type AccountId = u64; + } + + impl pallet_currency::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + } + } + + pub(crate) use runtime_v2::*; + + #[docify::export(transfer_works_v2)] + #[test] + fn transfer_works() { + StateBuilder::default().build_and_execute(|| { + // skip the genesis block, as events are not deposited there and we need them for + // the final assertion. + System::set_block_number(ALICE); + + // given the initial state, when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(ALICE), BOB, 50)); + + // then: + assert_eq!(Balances::::get(&ALICE), Some(50)); + assert_eq!(Balances::::get(&BOB), Some(150)); + assert_eq!(TotalIssuance::::get(), Some(200)); + + // now we can also check that an event has been deposited: + assert_eq!( + System::read_events_for_pallet::>(), + vec![Event::Transferred { from: ALICE, to: BOB, amount: 50 }] + ); + }); + } + } +} diff --git a/docs/sdk/packages/guides/first-runtime/Cargo.toml b/docs/sdk/packages/guides/first-runtime/Cargo.toml new file mode 100644 index 000000000000..303d5c5e7f5f --- /dev/null +++ b/docs/sdk/packages/guides/first-runtime/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "polkadot-sdk-docs-first-runtime" +description = "A simple runtime created for the polkadot-sdk-docs guides" +version = "0.0.0" +license = "MIT-0" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true +publish = false + +[lints] +workspace = true + +[dependencies] +codec = { workspace = true } +scale-info = { workspace = true } +serde_json = { workspace = true } + +# this is a frame-based runtime, thus importing `frame` with runtime feature enabled. +frame = { workspace = true, features = ["experimental", "runtime"] } + +# pallets that we want to use +pallet-balances = { workspace = true } +pallet-sudo = { workspace = true } +pallet-timestamp = { workspace = true } +pallet-transaction-payment = { workspace = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true } + +# other polkadot-sdk-deps +sp-keyring = { workspace = true } + +# local pallet templates +first-pallet = { workspace = true } + +docify = { workspace = true } + +[build-dependencies] +substrate-wasm-builder = { workspace = true, optional = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "serde_json/std", + + "frame/std", + + "pallet-balances/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + + "first-pallet/std", + "sp-keyring/std", + + "substrate-wasm-builder", +] diff --git a/docs/sdk/packages/guides/first-runtime/build.rs b/docs/sdk/packages/guides/first-runtime/build.rs new file mode 100644 index 000000000000..b7676a70dfe8 --- /dev/null +++ b/docs/sdk/packages/guides/first-runtime/build.rs @@ -0,0 +1,27 @@ +// 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. + +fn main() { + #[cfg(feature = "std")] + { + substrate_wasm_builder::WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build(); + } +} diff --git a/docs/sdk/packages/guides/first-runtime/src/lib.rs b/docs/sdk/packages/guides/first-runtime/src/lib.rs new file mode 100644 index 000000000000..61ca550c8750 --- /dev/null +++ b/docs/sdk/packages/guides/first-runtime/src/lib.rs @@ -0,0 +1,299 @@ +// 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. + +//! Runtime used in `your_first_runtime`. + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; +use alloc::{vec, vec::Vec}; +use first_pallet::pallet_v2 as our_first_pallet; +use frame::{ + prelude::*, + runtime::{apis, prelude::*}, +}; +use pallet_transaction_payment_rpc_runtime_api::{FeeDetails, RuntimeDispatchInfo}; + +#[docify::export] +#[runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + 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, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + system_version: 1, +}; + +#[docify::export(cr)] +construct_runtime!( + pub struct Runtime { + // Mandatory for all runtimes + System: frame_system, + + // A number of other pallets from FRAME. + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Sudo: pallet_sudo, + TransactionPayment: pallet_transaction_payment, + + // Our local pallet + FirstPallet: our_first_pallet, + } +); + +#[docify::export_content] +mod runtime_types { + use super::*; + pub(super) type SignedExtra = ( + // `frame` already provides all the signed extensions from `frame-system`. We just add the + // one related to tx-payment here. + frame::runtime::types_common::SystemTransactionExtensionsOf, + pallet_transaction_payment::ChargeTransactionPayment, + ); + + pub(super) type Block = frame::runtime::types_common::BlockOf; + pub(super) type Header = HeaderFor; + + pub(super) type RuntimeExecutive = Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + >; +} +use runtime_types::*; + +#[docify::export_content] +mod config_impls { + use super::*; + + parameter_types! { + pub const Version: RuntimeVersion = VERSION; + } + + #[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)] + impl frame_system::Config for Runtime { + type Block = Block; + type Version = Version; + type AccountData = + pallet_balances::AccountData<::Balance>; + } + + #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] + impl pallet_balances::Config for Runtime { + type AccountStore = System; + } + + #[derive_impl(pallet_sudo::config_preludes::TestDefaultConfig)] + impl pallet_sudo::Config for Runtime {} + + #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)] + impl pallet_timestamp::Config for Runtime {} + + #[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] + impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; + // We specify a fixed length to fee here, which essentially means all transactions charge + // exactly 1 unit of fee. + type LengthToFee = FixedFee<1, ::Balance>; + type WeightToFee = NoFee<::Balance>; + } +} + +#[docify::export(our_config_impl)] +impl our_first_pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +/// Provides getters for genesis configuration presets. +pub mod genesis_config_presets { + use super::*; + use crate::{ + 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; + build_struct_json_patch!(RuntimeGenesisConfig { + balances: BalancesConfig { + balances: AccountKeyring::iter() + .map(|a| (a.to_account_id(), endowment)) + .collect::>(), + }, + sudo: SudoConfig { key: Some(AccountKeyring::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.as_ref() { + DEV_RUNTIME_PRESET => development_config_genesis(), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) + } + + /// List of supported presets. + #[docify::export] + pub fn preset_names() -> Vec { + vec![PresetId::from(DEV_RUNTIME_PRESET)] + } +} + +impl_runtime_apis! { + impl apis::Core for Runtime { + fn version() -> RuntimeVersion { + VERSION + } + + fn execute_block(block: Block) { + RuntimeExecutive::execute_block(block) + } + + fn initialize_block(header: &Header) -> ExtrinsicInclusionMode { + RuntimeExecutive::initialize_block(header) + } + } + + impl apis::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + OpaqueMetadata::new(Runtime::metadata().into()) + } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> Vec { + Runtime::metadata_versions() + } + } + + impl apis::BlockBuilder for Runtime { + fn apply_extrinsic(extrinsic: ExtrinsicFor) -> ApplyExtrinsicResult { + RuntimeExecutive::apply_extrinsic(extrinsic) + } + + fn finalize_block() -> HeaderFor { + RuntimeExecutive::finalize_block() + } + + fn inherent_extrinsics(data: InherentData) -> Vec> { + data.create_extrinsics() + } + + fn check_inherents( + block: Block, + data: InherentData, + ) -> CheckInherentsResult { + data.check_extrinsics(&block) + } + } + + impl apis::TaggedTransactionQueue for Runtime { + fn validate_transaction( + source: TransactionSource, + tx: ExtrinsicFor, + block_hash: ::Hash, + ) -> TransactionValidity { + RuntimeExecutive::validate_transaction(source, tx, block_hash) + } + } + + impl apis::OffchainWorkerApi for Runtime { + fn offchain_worker(header: &HeaderFor) { + RuntimeExecutive::offchain_worker(header) + } + } + + impl apis::SessionKeys for Runtime { + fn generate_session_keys(_seed: Option>) -> Vec { + Default::default() + } + + fn decode_session_keys( + _encoded: Vec, + ) -> Option, apis::KeyTypeId)>> { + Default::default() + } + } + + impl apis::AccountNonceApi for Runtime { + fn account_nonce(account: interface::AccountId) -> interface::Nonce { + System::account_nonce(account) + } + } + + impl apis::GenesisBuilder for Runtime { + fn build_state(config: Vec) -> GenesisBuilderResult { + build_state::(config) + } + + fn get_preset(id: &Option) -> Option> { + get_preset::(id, self::genesis_config_presets::get_preset) + } + + fn preset_names() -> Vec { + crate::genesis_config_presets::preset_names() + } + } + + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< + Block, + interface::Balance, + > for Runtime { + fn query_info(uxt: ExtrinsicFor, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + fn query_fee_details(uxt: ExtrinsicFor, len: u32) -> FeeDetails { + TransactionPayment::query_fee_details(uxt, len) + } + fn query_weight_to_fee(weight: Weight) -> interface::Balance { + TransactionPayment::weight_to_fee(weight) + } + fn query_length_to_fee(length: u32) -> interface::Balance { + TransactionPayment::length_to_fee(length) + } + } +} + +/// Just a handy re-definition of some types based on what is already provided to the pallet +/// configs. +pub mod interface { + use super::Runtime; + use frame::prelude::frame_system; + + pub type AccountId = ::AccountId; + pub type Nonce = ::Nonce; + pub type Hash = ::Hash; + pub type Balance = ::Balance; + pub type MinimumBalance = ::ExistentialDeposit; +} diff --git a/docs/sdk/src/external_resources.rs b/docs/sdk/src/external_resources.rs new file mode 100644 index 000000000000..939874d12f13 --- /dev/null +++ b/docs/sdk/src/external_resources.rs @@ -0,0 +1,14 @@ +//! # External Resources +//! +//! A non-exhaustive, un-opinionated list of external resources about Polkadot SDK. +//! +//! Unlike [`crate::guides`], or [`crate::polkadot_sdk::templates`] that contain material directly +//! maintained in the `polkadot-sdk` repository, the list of resources here are maintained by +//! third-parties, and are therefore subject to more variability. Any further resources may be added +//! by opening a pull request to the `polkadot-sdk` repository. +//! +//! - [Polkadot NFT Marketplace Tutorial by Polkadot Fellow Shawn Tabrizi](https://www.shawntabrizi.com/substrate-collectables-workshop/) +//! - [DOT Code School](https://dotcodeschool.com/) +//! - [Polkadot Developers](https://github.com/polkadot-developers/) +//! - [Polkadot Blockchain Academy](https://github.com/Polkadot-Blockchain-Academy) +//! - [Polkadot Wiki: Build](https://wiki.polkadot.network/docs/build-guide) diff --git a/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs b/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs index 14a0b6107966..2339088abed4 100644 --- a/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs +++ b/docs/sdk/src/guides/enable_elastic_scaling_mvp.rs @@ -70,10 +70,11 @@ //! - Ensure enough coretime is assigned to the parachain. For maximum throughput the upper bound is //! 3 cores. //! -//!
Phase 1 is not needed if using the polkadot-parachain binary -//! built from the latest polkadot-sdk release! Simply pass the -//! --experimental-use-slot-based parameter to the command line and jump to Phase -//! 2.
+//!
Phase 1 is NOT needed if using the polkadot-parachain or +//! polkadot-omni-node binary, or polkadot-omni-node-lib built from the +//! latest polkadot-sdk release! Simply pass the --experimental-use-slot-based +//! ([`polkadot_omni_node_lib::cli::Cli::experimental_use_slot_based`]) parameter to the command +//! line and jump to Phase 2.
//! //! The following steps assume using the cumulus parachain template. //! @@ -85,7 +86,7 @@ //! This phase consists of plugging in the new slot-based collator. //! //! 1. In `node/src/service.rs` import the slot based collator instead of the lookahead collator. -#![doc = docify::embed!("../../cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/aura.rs", slot_based_colator_import)] +#![doc = docify::embed!("../../cumulus/polkadot-omni-node/lib/src/nodes/aura.rs", slot_based_colator_import)] //! //! 2. In `start_consensus()` //! - Remove the `overseer_handle` param (also remove the @@ -94,7 +95,7 @@ //! `slot_drift` field with a value of `Duration::from_secs(1)`. //! - Replace the single future returned by `aura::run` with the two futures returned by it and //! spawn them as separate tasks: -#![doc = docify::embed!("../../cumulus/polkadot-parachain/polkadot-parachain-lib/src/nodes/aura.rs", launch_slot_based_collator)] +#![doc = docify::embed!("../../cumulus/polkadot-omni-node/lib/src/nodes/aura.rs", launch_slot_based_collator)] //! //! 3. In `start_parachain_node()` remove the `overseer_handle` param passed to `start_consensus`. //! diff --git a/docs/sdk/src/guides/enable_pov_reclaim.rs b/docs/sdk/src/guides/enable_pov_reclaim.rs index 13b27d18956b..cb6960b3df4e 100644 --- a/docs/sdk/src/guides/enable_pov_reclaim.rs +++ b/docs/sdk/src/guides/enable_pov_reclaim.rs @@ -58,9 +58,9 @@ //! > that this step in the guide was not //! > set up correctly. //! -//! ## 3. Add the SignedExtension to your runtime +//! ## 3. Add the TransactionExtension to your runtime //! -//! In your runtime, you will find a list of SignedExtensions. +//! In your runtime, you will find a list of TransactionExtensions. //! To enable the reclaiming, //! add [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim) //! to that list. For maximum efficiency, make sure that `StorageWeightReclaim` is last in the list. diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs index a7fd146ccdf3..747128a728d0 100644 --- a/docs/sdk/src/guides/mod.rs +++ b/docs/sdk/src/guides/mod.rs @@ -1,14 +1,22 @@ //! # Polkadot SDK Docs Guides //! -//! This crate contains a collection of guides that are foundational to the developers of Polkadot -//! SDK. They are common user-journeys that are traversed in the Polkadot ecosystem. +//! This crate contains a collection of guides that are foundational to the developers of +//! Polkadot SDK. They are common user-journeys that are traversed in the Polkadot ecosystem. //! -//! 1. [`crate::guides::your_first_pallet`] is your starting point with Polkadot SDK. It contains -//! the basics of -//! building a simple crypto currency with FRAME. -//! 2. [`crate::guides::your_first_runtime`] is the next step in your journey. It contains the -//! basics of building a runtime that contains this pallet, plus a few common pallets from FRAME. +//! The main user-journey covered by these guides is: //! +//! * [`your_first_pallet`], where you learn what a FRAME pallet is, and write your first +//! application logic. +//! * [`your_first_runtime`], where you learn how to compile your pallets into a WASM runtime. +//! * [`your_first_node`], where you learn how to run the said runtime in a node. +//! +//! > By this step, you have already launched a full Polkadot-SDK-based blockchain! +//! +//! Once done, feel free to step up into one of our templates: [`crate::polkadot_sdk::templates`]. +//! +//! [`your_first_pallet`]: crate::guides::your_first_pallet +//! [`your_first_runtime`]: crate::guides::your_first_runtime +//! [`your_first_node`]: crate::guides::your_first_node //! //! Other guides are related to other miscellaneous topics and are listed as modules below. @@ -19,19 +27,12 @@ pub mod your_first_pallet; /// compiling it to [WASM](crate::polkadot_sdk::substrate#wasm-build). pub mod your_first_runtime; -// /// Running the given runtime with a node. No specific consensus mechanism is used at this stage. -// TODO -// pub mod your_first_node; - -// /// How to enhance a given runtime and node to be cumulus-enabled, run it as a parachain -// /// and connect it to a relay-chain. -// TODO -// pub mod cumulus_enabled_parachain; +/// Running the given runtime with a node. No specific consensus mechanism is used at this stage. +pub mod your_first_node; -// /// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between -// /// itself and the relay chain to which it is connected. -// TODO -// pub mod xcm_enabled_parachain; +/// How to enhance a given runtime and node to be cumulus-enabled, run it as a parachain +/// and connect it to a relay-chain. +// pub mod your_first_parachain; /// How to enable storage weight reclaiming in a parachain node and runtime. pub mod enable_pov_reclaim; diff --git a/docs/sdk/src/guides/your_first_node.rs b/docs/sdk/src/guides/your_first_node.rs index d12349c99063..da37c11c206f 100644 --- a/docs/sdk/src/guides/your_first_node.rs +++ b/docs/sdk/src/guides/your_first_node.rs @@ -1 +1,314 @@ //! # Your first Node +//! +//! In this guide, you will learn how to run a runtime, such as the one created in +//! [`your_first_runtime`], in a node. Within the context of this guide, we will focus on running +//! the runtime with an [`omni-node`]. Please first read this page to learn about the OmniNode, and +//! other options when it comes to running a node. +//! +//! [`your_first_runtime`] is a runtime with no consensus related code, and therefore can only be +//! executed with a node that also expects no consensus ([`sc_consensus_manual_seal`]). +//! `polkadot-omni-node`'s [`--dev-block-time`] precisely does this. +//! +//! > All of the following steps are coded as unit tests of this module. Please see `Source` of the +//! > page for more information. +//! +//! ## Running The Omni Node +//! +//! ### Installs +//! +//! The `polkadot-omni-node` can either be downloaded from the latest [Release](https://github.com/paritytech/polkadot-sdk/releases/) of `polkadot-sdk`, +//! or installed using `cargo`: +//! +//! ```text +//! cargo install polkadot-omni-node +//! ``` +//! +//! Next, we need to install the [`chain-spec-builder`]. This is the tool that allows us to build +//! chain-specifications, through interacting with the genesis related APIs of the runtime, as +//! described in [`crate::guides::your_first_runtime#genesis-configuration`]. +//! +//! ```text +//! cargo install staging-chain-spec-builder +//! ``` +//! +//! > The name of the crate is prefixed with `staging` as the crate name `chain-spec-builder` on +//! > crates.io is already taken and is not controlled by `polkadot-sdk` developers. +//! +//! ### Building Runtime +//! +//! Next, we need to build the corresponding runtime that we wish to interact with. +//! +//! ```text +//! cargo build --release -p path-to-runtime +//! ``` +//! Equivalent code in tests: +#![doc = docify::embed!("./src/guides/your_first_node.rs", build_runtime)] +//! +//! This creates the wasm file under `./target/{release}/wbuild/release` directory. +//! +//! ### Building Chain Spec +//! +//! Next, we can generate the corresponding chain-spec file. For this example, we will use the +//! `development` (`sp_genesis_config::DEVELOPMENT`) preset. +//! +//! Note that we intend to run this chain-spec with `polkadot-omni-node`, which is tailored for +//! running parachains. This requires the chain-spec to always contain the `para_id` and a +//! `relay_chain` fields, which are provided below as CLI arguments. +//! +//! ```text +//! chain-spec-builder \ +//! -c \ +//! create \ +//! --para-id 42 \ +//! --relay-chain dontcare \ +//! --runtime polkadot_sdk_docs_first_runtime.wasm \ +//! named-preset development +//! ``` +//! +//! Equivalent code in tests: +#![doc = docify::embed!("./src/guides/your_first_node.rs", csb)] +//! +//! +//! ### Running `polkadot-omni-node` +//! +//! Finally, we can run the node with the generated chain-spec file. We can also specify the block +//! time using the `--dev-block-time` flag. +//! +//! ```text +//! polkadot-omni-node \ +//! --tmp \ +//! --dev-block-time 1000 \ +//! --chain .json +//! ``` +//! +//! > Note that we always prefer to use `--tmp` for testing, as it will save the chain state to a +//! > temporary folder, allowing the chain-to be easily restarted without `purge-chain`. See +//! > [`sc_cli::commands::PurgeChainCmd`] and [`sc_cli::commands::RunCmd::tmp`] for more info. +//! +//! This will start the node and import the blocks. Note while using `--dev-block-time`, the node +//! will use the testing-specific manual-seal consensus. This is an efficient way to test the +//! application logic of your runtime, without needing to yet care about consensus, block +//! production, relay-chain and so on. +//! +//! ### Next Steps +//! +//! * See the rest of the steps in [`crate::reference_docs::omni_node#user-journey`]. +//! +//! [`runtime`]: crate::reference_docs::glossary#runtime +//! [`node`]: crate::reference_docs::glossary#node +//! [`build_config`]: first_runtime::Runtime#method.build_config +//! [`omni-node`]: crate::reference_docs::omni_node +//! [`--dev-block-time`]: (polkadot_omni_node_lib::cli::Cli::dev_block_time) + +#[cfg(test)] +mod tests { + use assert_cmd::Command; + use rand::Rng; + use sc_chain_spec::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET}; + use sp_genesis_builder::PresetId; + use std::path::PathBuf; + + const PARA_RUNTIME: &'static str = "parachain-template-runtime"; + const FIRST_RUNTIME: &'static str = "polkadot-sdk-docs-first-runtime"; + const MINIMAL_RUNTIME: &'static str = "minimal-template-runtime"; + + const CHAIN_SPEC_BUILDER: &'static str = "chain-spec-builder"; + const OMNI_NODE: &'static str = "polkadot-omni-node"; + + fn cargo() -> Command { + Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())) + } + + fn get_target_directory() -> Option { + let output = cargo().arg("metadata").arg("--format-version=1").output().ok()?; + + if !output.status.success() { + return None; + } + + let metadata: serde_json::Value = serde_json::from_slice(&output.stdout).ok()?; + let target_directory = metadata["target_directory"].as_str()?; + + Some(PathBuf::from(target_directory)) + } + + fn find_release_binary(name: &str) -> Option { + let target_dir = get_target_directory()?; + let release_path = target_dir.join("release").join(name); + + if release_path.exists() { + Some(release_path) + } else { + None + } + } + + fn find_wasm(runtime_name: &str) -> Option { + let target_dir = get_target_directory()?; + let wasm_path = target_dir + .join("release") + .join("wbuild") + .join(runtime_name) + .join(format!("{}.wasm", runtime_name.replace('-', "_"))); + + if wasm_path.exists() { + Some(wasm_path) + } else { + None + } + } + + fn maybe_build_runtimes() { + if find_wasm(&PARA_RUNTIME).is_none() { + println!("Building parachain-template-runtime..."); + Command::new("cargo") + .arg("build") + .arg("--release") + .arg("-p") + .arg(PARA_RUNTIME) + .assert() + .success(); + } + if find_wasm(&FIRST_RUNTIME).is_none() { + 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(); + } + build_runtime() + } + + assert!(find_wasm(PARA_RUNTIME).is_some()); + assert!(find_wasm(FIRST_RUNTIME).is_some()); + } + + fn maybe_build_chain_spec_builder() { + if find_release_binary(CHAIN_SPEC_BUILDER).is_none() { + println!("Building chain-spec-builder..."); + Command::new("cargo") + .arg("build") + .arg("--release") + .arg("-p") + .arg("staging-chain-spec-builder") + .assert() + .success(); + } + assert!(find_release_binary(CHAIN_SPEC_BUILDER).is_some()); + } + + fn maybe_build_omni_node() { + if find_release_binary(OMNI_NODE).is_none() { + println!("Building polkadot-omni-node..."); + Command::new("cargo") + .arg("build") + .arg("--release") + .arg("-p") + .arg("polkadot-omni-node") + .assert() + .success(); + } + } + + fn test_runtime_preset(runtime: &'static str, block_time: u64, maybe_preset: Option) { + sp_tracing::try_init_simple(); + maybe_build_runtimes(); + maybe_build_chain_spec_builder(); + maybe_build_omni_node(); + + let chain_spec_builder = + find_release_binary(&CHAIN_SPEC_BUILDER).expect("we built it above; qed"); + let omni_node = find_release_binary(OMNI_NODE).expect("we built it above; qed"); + let runtime_path = find_wasm(runtime).expect("we built it above; qed"); + + let random_seed: u32 = rand::thread_rng().gen(); + let chain_spec_file = std::env::current_dir() + .unwrap() + .join(format!("{}_{}_{}.json", runtime, block_time, random_seed)); + + Command::new(chain_spec_builder) + .args(["-c", chain_spec_file.to_str().unwrap()]) + .arg("create") + .args(["--para-id", "1000", "--relay-chain", "dontcare"]) + .args(["-r", runtime_path.to_str().unwrap()]) + .args(match maybe_preset { + Some(preset) => vec!["named-preset".to_string(), preset.to_string()], + None => vec!["default".to_string()], + }) + .assert() + .success(); + + let output = Command::new(omni_node) + .arg("--tmp") + .args(["--chain", chain_spec_file.to_str().unwrap()]) + .args(["--dev-block-time", block_time.to_string().as_str()]) + .timeout(std::time::Duration::from_secs(10)) + .output() + .unwrap(); + + std::fs::remove_file(chain_spec_file).unwrap(); + + // uncomment for debugging. + // println!("output: {:?}", output); + + let expected_blocks = (10_000 / block_time).saturating_div(2); + assert!(expected_blocks > 0, "test configuration is bad, should give it more time"); + assert!(String::from_utf8(output.stderr) + .unwrap() + .contains(format!("Imported #{}", expected_blocks).to_string().as_str())); + } + + #[test] + fn works_with_different_block_times() { + test_runtime_preset(PARA_RUNTIME, 100, Some(DEV_RUNTIME_PRESET.into())); + test_runtime_preset(PARA_RUNTIME, 3000, Some(DEV_RUNTIME_PRESET.into())); + + // we need this snippet just for docs + #[docify::export_content(csb)] + fn build_para_chain_spec_works() { + 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(); + std::fs::remove_file(output).unwrap(); + } + build_para_chain_spec_works(); + } + + #[test] + fn parachain_runtime_works() { + // TODO: None doesn't work. But maybe it should? it would be misleading as many users might + // use it. + [Some(DEV_RUNTIME_PRESET.into()), Some(LOCAL_TESTNET_RUNTIME_PRESET.into())] + .into_iter() + .for_each(|preset| { + test_runtime_preset(PARA_RUNTIME, 1000, preset); + }); + } + + #[test] + fn minimal_runtime_works() { + [None, Some(DEV_RUNTIME_PRESET.into())].into_iter().for_each(|preset| { + test_runtime_preset(MINIMAL_RUNTIME, 1000, preset); + }); + } + + #[test] + fn guide_first_runtime_works() { + [Some(DEV_RUNTIME_PRESET.into())].into_iter().for_each(|preset| { + test_runtime_preset(FIRST_RUNTIME, 1000, preset); + }); + } +} diff --git a/docs/sdk/src/guides/your_first_pallet/mod.rs b/docs/sdk/src/guides/your_first_pallet/mod.rs index fcfaab00e552..aef8981b4d4a 100644 --- a/docs/sdk/src/guides/your_first_pallet/mod.rs +++ b/docs/sdk/src/guides/your_first_pallet/mod.rs @@ -47,7 +47,7 @@ //! //! [`pallet::config`] and [`pallet::pallet`] are both mandatory parts of any //! pallet. Refer to the documentation of each to get an overview of what they do. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", shell_pallet)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", shell_pallet)] //! //! All of the code that follows in this guide should live inside of the `mod pallet`. //! @@ -61,17 +61,17 @@ //! > For the rest of this guide, we will opt for a balance type of `u128`. For the sake of //! > simplicity, we are hardcoding this type. In a real pallet is best practice to define it as a //! > generic bounded type in the `Config` trait, and then specify it in the implementation. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Balance)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Balance)] //! //! The definition of these two storage items, based on [`pallet::storage`] details, is as follows: -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", TotalIssuance)] -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Balances)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", TotalIssuance)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Balances)] //! //! ### Dispatchables //! //! Next, we will define the dispatchable functions. As per [`pallet::call`], these will be defined //! as normal `fn`s attached to `struct Pallet`. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_pallet)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_pallet)] //! //! The logic of these functions is self-explanatory. Instead, we will focus on the FRAME-related //! details: @@ -108,14 +108,14 @@ //! How we handle error in the above snippets is fairly rudimentary. Let's look at how this can be //! improved. First, we can use [`frame::prelude::ensure`] to express the error slightly better. //! This macro will call `.into()` under the hood. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_better)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_better)] //! //! Moreover, you will learn in the [Defensive Programming //! section](crate::reference_docs::defensive_programming) that it is always recommended to use //! safe arithmetic operations in your runtime. By using [`frame::traits::CheckedSub`], we can not //! only take a step in that direction, but also improve the error handing and make it slightly more //! ergonomic. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_better_checked)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_better_checked)] //! //! This is more or less all the logic that there is in this basic currency pallet! //! @@ -145,7 +145,7 @@ //! through [`frame::runtime::prelude::construct_runtime`]. All runtimes also have to include //! [`frame::prelude::frame_system`]. So we expect to see a runtime with two pallet, `frame_system` //! and the one we just wrote. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", runtime)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", runtime)] //! //! > [`frame::pallet_macros::derive_impl`] is a FRAME feature that enables developers to have //! > defaults for associated types. @@ -182,7 +182,7 @@ //! to learn is that all of your pallet testing code should be wrapped in //! [`frame::testing_prelude::TestState`]. This is a type that provides access to an in-memory state //! to be used in our tests. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", first_test)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", first_test)] //! //! In the first test, we simply assert that there is no total issuance, and no balance associated //! with Alice's account. Then, we mint some balance into Alice's, and re-check. @@ -206,16 +206,16 @@ //! //! Let's see how we can implement a better test setup using this pattern. First, we define a //! `struct StateBuilder`. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", StateBuilder)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", StateBuilder)] //! //! This struct is meant to contain the same list of accounts and balances that we want to have at //! the beginning of each block. We hardcoded this to `let accounts = vec![(ALICE, 100), (2, 100)];` //! so far. Then, if desired, we attach a default value for this struct. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", default_state_builder)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", default_state_builder)] //! //! Like any other builder pattern, we attach functions to the type to mutate its internal //! properties. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_state_builder_add)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_state_builder_add)] //! //! Finally --the useful part-- we write our own custom `build_and_execute` function on //! this type. This function will do multiple things: @@ -227,23 +227,23 @@ //! after each test. For example, in this test, we do some additional checking about the //! correctness of the `TotalIssuance`. We leave it up to you as an exercise to learn why the //! assertion should always hold, and how it is checked. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_state_builder_build)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_state_builder_build)] //! //! We can write tests that specifically check the initial state, and making sure our `StateBuilder` //! is working exactly as intended. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", state_builder_works)] -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", state_builder_add_balance)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", state_builder_works)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", state_builder_add_balance)] //! //! ### More Tests //! //! Now that we have a more ergonomic test setup, let's see how a well written test for transfer and //! mint would look like. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_works)] -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", mint_works)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_works)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", mint_works)] //! //! It is always a good idea to build a mental model where you write *at least* one test for each //! "success path" of a dispatchable, and one test for each "failure path", such as: -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_from_non_existent_fails)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_from_non_existent_fails)] //! //! We leave it up to you to write a test that triggers the `InsufficientBalance` error. //! @@ -272,8 +272,8 @@ //! With the explanation out of the way, let's see how these components can be added. Both follow a //! fairly familiar syntax: normal Rust enums, with extra [`pallet::event`] and [`pallet::error`] //! attributes attached. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Event)] -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Error)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Event)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Error)] //! //! One slightly custom part of this is the [`pallet::generate_deposit`] part. Without going into //! too much detail, in order for a pallet to emit events to the rest of the system, it needs to do @@ -288,17 +288,17 @@ //! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME //! provides a default way of storing events, and this is what [`pallet::generate_deposit`] is //! doing. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", config_v2)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", config_v2)] //! //! > These `Runtime*` types are better explained in //! > [`crate::reference_docs::frame_runtime_types`]. //! //! Then, we can rewrite the `transfer` dispatchable as such: -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_v2)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_v2)] //! //! Then, notice how now we would need to provide this `type RuntimeEvent` in our test runtime //! setup. -#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", runtime_v2)] +#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", runtime_v2)] //! //! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent = //! RuntimeEvent`) is generated by diff --git a/docs/sdk/src/guides/your_first_pallet/with_event.rs b/docs/sdk/src/guides/your_first_pallet/with_event.rs deleted file mode 100644 index a5af29c9c319..000000000000 --- a/docs/sdk/src/guides/your_first_pallet/with_event.rs +++ /dev/null @@ -1,101 +0,0 @@ -#[frame::pallet(dev_mode)] -pub mod pallet { - use frame::prelude::*; - - #[docify::export] - pub type Balance = u128; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - pub struct Pallet(_); - - #[docify::export] - /// Single storage item, of type `Balance`. - #[pallet::storage] - pub type TotalIssuance = StorageValue<_, Balance>; - - #[docify::export] - /// A mapping from `T::AccountId` to `Balance` - #[pallet::storage] - pub type Balances = StorageMap<_, _, T::AccountId, Balance>; - - #[docify::export(impl_pallet)] - #[pallet::call] - impl Pallet { - /// An unsafe mint that can be called by anyone. Not a great idea. - pub fn mint_unsafe( - origin: T::RuntimeOrigin, - dest: T::AccountId, - amount: Balance, - ) -> DispatchResult { - // ensure that this is a signed account, but we don't really check `_anyone`. - let _anyone = ensure_signed(origin)?; - - // update the balances map. Notice how all `` remains as ``. - Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); - // update total issuance. - TotalIssuance::::mutate(|t| *t = Some(t.unwrap_or(0) + amount)); - - Ok(()) - } - - /// Transfer `amount` from `origin` to `dest`. - pub fn transfer( - origin: T::RuntimeOrigin, - dest: T::AccountId, - amount: Balance, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - // ensure sender has enough balance, and if so, calculate what is left after `amount`. - let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; - if sender_balance < amount { - return Err("NotEnoughBalance".into()) - } - let remainder = sender_balance - amount; - - // update sender and dest balances. - Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); - Balances::::insert(&sender, remainder); - - Ok(()) - } - } - - #[allow(unused)] - impl Pallet { - #[docify::export] - pub fn transfer_better( - origin: T::RuntimeOrigin, - dest: T::AccountId, - amount: Balance, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; - ensure!(sender_balance >= amount, "NotEnoughBalance"); - let remainder = sender_balance - amount; - - // .. snip - Ok(()) - } - - #[docify::export] - /// Transfer `amount` from `origin` to `dest`. - pub fn transfer_better_checked( - origin: T::RuntimeOrigin, - dest: T::AccountId, - amount: Balance, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; - let remainder = sender_balance.checked_sub(amount).ok_or("NotEnoughBalance")?; - - // .. snip - Ok(()) - } - } -} diff --git a/docs/sdk/src/guides/your_first_runtime.rs b/docs/sdk/src/guides/your_first_runtime.rs index c58abc1120c1..79f01e66979a 100644 --- a/docs/sdk/src/guides/your_first_runtime.rs +++ b/docs/sdk/src/guides/your_first_runtime.rs @@ -1,3 +1,170 @@ //! # Your first Runtime //! -//! 🚧 +//! This guide will walk you through the steps to add your pallet to a runtime. +//! +//! The good news is, in [`crate::guides::your_first_pallet`], we have already created a _test_ +//! runtime that was used for testing, and a real runtime is not that much different! +//! +//! ## Setup +//! +//! A runtime shares a few similar setup requirements as with a pallet: +//! +//! * importing [`frame`], [`codec`], and [`scale_info`] crates. +//! * following the [`std` feature-gating](crate::polkadot_sdk::substrate#wasm-build) pattern. +//! +//! But, more specifically, it also contains: +//! +//! * a `build.rs` that uses [`substrate_wasm_builder`]. This entails declaring +//! `[build-dependencies]` in the Cargo manifest file: +//! +//! ```ignore +//! [build-dependencies] +//! substrate-wasm-builder = { ... } +//! ``` +//! +//! >Note that a runtime must always be one-runtime-per-crate. You cannot define multiple runtimes +//! per rust crate. +//! +//! You can find the full code of this guide in [`first_runtime`]. +//! +//! ## Your First Runtime +//! +//! The first new property of a real runtime that it must define its +//! [`frame::runtime::prelude::RuntimeVersion`]: +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", VERSION)] +//! +//! The version contains a number of very important fields, such as `spec_version` and `spec_name` +//! that play an important role in identifying your runtime and its version, more importantly in +//! runtime upgrades. More about runtime upgrades in +//! [`crate::reference_docs::frame_runtime_upgrades_and_migrations`]. +//! +//! Then, a real runtime also contains the `impl` of all individual pallets' `trait Config` for +//! `struct Runtime`, and a [`frame::runtime::prelude::construct_runtime`] macro that amalgamates +//! them all. +//! +//! In the case of our example: +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", our_config_impl)] +//! +//! In this example, we bring in a number of other pallets from [`frame`] into the runtime, each of +//! their `Config` need to be implemented for `struct Runtime`: +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", config_impls)] +//! +//! Notice how we use [`frame::pallet_macros::derive_impl`] to provide "default" configuration items +//! for each pallet. Feel free to dive into the definition of each default prelude (eg. +//! [`frame::prelude::frame_system::pallet::config_preludes`]) to learn more which types are exactly +//! used. +//! +//! Recall that in test runtime in [`crate::guides::your_first_pallet`], we provided `type AccountId +//! = u64` to `frame_system`, while in this case we rely on whatever is provided by +//! [`SolochainDefaultConfig`], which is indeed a "real" 32 byte account id. +//! +//! Then, a familiar instance of `construct_runtime` amalgamates all of the pallets: +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", cr)] +//! +//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that every (real) runtime needs to +//! implement a set of runtime APIs that will then let the node to communicate with it. The final +//! steps of crafting a runtime are related to achieving exactly this. +//! +//! First, we define a number of types that eventually lead to the creation of an instance of +//! [`frame::runtime::prelude::Executive`]. The executive is a handy FRAME utility that, through +//! amalgamating all pallets and further types, implements some of the very very core pieces of the +//! runtime logic, such as how blocks are executed and other runtime-api implementations. +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", runtime_types)] +//! +//! Finally, we use [`frame::runtime::prelude::impl_runtime_apis`] to implement all of the runtime +//! APIs that the runtime wishes to expose. As you will see in the code, most of these runtime API +//! implementations are merely forwarding calls to `RuntimeExecutive` which handles the actual +//! logic. Given that the implementation block is somewhat large, we won't repeat it here. You can +//! look for `impl_runtime_apis!` in [`first_runtime`]. +//! +//! ```ignore +//! impl_runtime_apis! { +//! impl apis::Core for Runtime { +//! fn version() -> RuntimeVersion { +//! VERSION +//! } +//! +//! fn execute_block(block: Block) { +//! RuntimeExecutive::execute_block(block) +//! } +//! +//! fn initialize_block(header: &Header) -> ExtrinsicInclusionMode { +//! RuntimeExecutive::initialize_block(header) +//! } +//! } +//! +//! // many more trait impls... +//! } +//! ``` +//! +//! And that more or less covers the details of how you would write a real runtime! +//! +//! Once you compile a crate that contains a runtime as above, simply running `cargo build` will +//! generate the wasm blobs and place them under `./target/release/wbuild`, as explained +//! [here](crate::polkadot_sdk::substrate#wasm-build). +//! +//! ## Genesis Configuration +//! +//! Every runtime specifies a number of runtime APIs that help the outer world (most notably, a +//! `node`) know what is the genesis state of this runtime. These APIs are then used to generate +//! what is known as a **Chain Specification, or chain spec for short**. A chain spec is the +//! primary way to run a new chain. +//! +//! These APIs are defined in [`sp_genesis_builder`], and are re-exposed as a part of +//! [`frame::runtime::apis`]. Therefore, the implementation blocks can be found inside of +//! `impl_runtime_apis!` similar to: +//! +//! ```ignore +//! impl_runtime_apis! { +//! impl apis::GenesisBuilder for Runtime { +//! fn build_state(config: Vec) -> GenesisBuilderResult { +//! build_state::(config) +//! } +//! +//! fn get_preset(id: &Option) -> Option> { +//! get_preset::(id, self::genesis_config_presets::get_preset) +//! } +//! +//! fn preset_names() -> Vec { +//! crate::genesis_config_presets::preset_names() +//! } +//! } +//! +//! } +//! ``` +//! +//! The implementation of these function can naturally vary from one runtime to the other, but the +//! overall pattern is common. For the case of this runtime, we do the following: +//! +//! 1. Expose one non-default preset, namely [`sp_genesis_builder::DEV_RUNTIME_PRESET`]. This means +//! our runtime has two "presets" of genesis state in total: `DEV_RUNTIME_PRESET` and `None`. +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", preset_names)] +//! +//! For `build_state` and `get_preset`, we use the helper functions provide by frame: +//! +//! * [`frame::runtime::prelude::build_state`] and [`frame::runtime::prelude::get_preset`]. +//! +//! Indeed, our runtime needs to specify what its `DEV_RUNTIME_PRESET` genesis state should be like: +#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", development_config_genesis)] +//! +//! For more in-depth information about `GenesisConfig`, `ChainSpec`, the `GenesisBuilder` API and +//! `chain-spec-builder`, see [`crate::reference_docs::chain_spec_genesis`]. +//! +//! ## Next Step +//! +//! See [`crate::guides::your_first_node`]. +//! +//! ## Further Reading +//! +//! 1. To learn more about signed extensions, see [`crate::reference_docs::signed_extensions`]. +//! 2. `AllPalletsWithSystem` is also generated by `construct_runtime`, as explained in +//! [`crate::reference_docs::frame_runtime_types`]. +//! 3. `Executive` supports more generics, most notably allowing the runtime to configure more +//! runtime migrations, as explained in +//! [`crate::reference_docs::frame_runtime_upgrades_and_migrations`]. +//! 4. Learn more about adding and implementing runtime apis in +//! [`crate::reference_docs::custom_runtime_api_rpc`]. +//! 5. To see a complete example of a runtime+pallet that is similar to this guide, please see +//! [`crate::polkadot_sdk::templates`]. +//! +//! [`SolochainDefaultConfig`]: struct@frame_system::pallet::config_preludes::SolochainDefaultConfig diff --git a/docs/sdk/src/lib.rs b/docs/sdk/src/lib.rs index 35f73c290bf2..e2c5fc93479c 100644 --- a/docs/sdk/src/lib.rs +++ b/docs/sdk/src/lib.rs @@ -5,9 +5,6 @@ //! This crate is a *minimal*, but *always-accurate* source of information for those wishing to //! build on the Polkadot SDK. //! -//! > **Work in Progress**: This crate is under heavy development. Expect content to be moved and -//! > changed. Do not use links to this crate yet. See [`meta_contributing`] for more information. -//! //! ## Getting Started //! //! We suggest the following reading sequence: @@ -15,7 +12,8 @@ //! - Start by learning about the the [`polkadot_sdk`], its structure and context. //! - Then, head over to the [`guides`]. This modules contains in-depth guides about the most //! important user-journeys of the Polkadot SDK. -//! - Whilst reading the guides, you might find back-links to [`reference_docs`]. +//! - Whilst reading the guides, you might find back-links to [`reference_docs`]. +//! - [`external_resources`] for a list of 3rd party guides and tutorials. //! - Finally, is the parent website of this crate that contains the //! list of further tools related to the Polkadot SDK. //! @@ -35,9 +33,13 @@ /// how one can contribute to it. pub mod meta_contributing; +/// A list of external resources and learning material about Polkadot SDK. +pub mod external_resources; + /// In-depth guides about the most common components of the Polkadot SDK. They are slightly more /// high level and broad than [`reference_docs`]. pub mod guides; + /// An introduction to the Polkadot SDK. Read this module to learn about the structure of the SDK, /// the tools that are provided as a part of it, and to gain a high level understanding of each. pub mod polkadot_sdk; diff --git a/docs/sdk/src/meta_contributing.rs b/docs/sdk/src/meta_contributing.rs index e1297151b231..d68d9bca18b1 100644 --- a/docs/sdk/src/meta_contributing.rs +++ b/docs/sdk/src/meta_contributing.rs @@ -69,7 +69,8 @@ //! > what topics are already covered in this crate, and how you can build on top of the information //! > that they already pose, rather than repeating yourself**. //! -//! For more details see the [latest documenting guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/DOCUMENTATION_GUIDELINES.md). +//! For more details see the [latest documenting +//! guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/DOCUMENTATION_GUIDELINES.md). //! //! #### Example: Explaining `#[pallet::call]` //! @@ -132,6 +133,13 @@ //! compromise, but in the long term, we should work towards finding a way to maintain different //! revisions of this crate. //! +//! ## Versioning +//! +//! So long as not deployed in `crates.io`, please notice that all of the information in this crate, +//! namely in [`crate::guides`] and such are compatible with the master branch of `polkadot-sdk`. A +//! few solutions have been proposed to improve this, please see +//! [here](https://github.com/paritytech/polkadot-sdk/issues/6191). +//! //! ## How to Develop Locally //! //! To view the docs specific [`crate`] locally for development, including the correct HTML headers diff --git a/docs/sdk/src/polkadot_sdk/mod.rs b/docs/sdk/src/polkadot_sdk/mod.rs index 32cad72fba7e..bf7346b871a1 100644 --- a/docs/sdk/src/polkadot_sdk/mod.rs +++ b/docs/sdk/src/polkadot_sdk/mod.rs @@ -75,6 +75,26 @@ //! runtimes are located under the //! [`polkadot-fellows/runtimes`](https://github.com/polkadot-fellows/runtimes) repository. //! +//! ### Binaries +//! +//! The main binaries that are part of the Polkadot SDK are: + +//! * [`polkadot`]: The Polkadot relay chain node binary, as noted above. +//! * [`polkadot-omni-node`]: A white-labeled parachain collator node. See more in +//! [`crate::reference_docs::omni_node`]. +//! * [`polkadot-parachain-bin`]: The collator node used to run collators for all Polkadot system +//! parachains. +//! * [`frame-omni-bencher`]: a benchmarking tool for FRAME-based runtimes. Nodes typically contain +//! a +//! `benchmark` subcommand that does the same. +//! * [`chain_spec_builder`]: Utility to build chain-specs Nodes typically contain a `build-spec` +//! subcommand that does the same. +//! * [`subkey`]: Substrate's key management utility. +//! * [`substrate-node`](node_cli) is an extensive substrate node that contains the superset of all +//! runtime and node side features. The corresponding runtime, called [`kitchensink_runtime`] +//! contains all of the modules that are provided with `FRAME`. This node and runtime is only used +//! for testing and demonstration. +//! //! ### Summary //! //! The following diagram summarizes how some of the components of Polkadot SDK work together: @@ -106,15 +126,19 @@ //! A list of projects and tools in the blockchain ecosystem that one way or another use parts of //! the Polkadot SDK: //! -//! * [Polygon's spin-off, Avail](https://github.com/availproject/avail) +//! * [Avail](https://github.com/availproject/avail) //! * [Cardano Partner Chains](https://iohk.io/en/blog/posts/2023/11/03/partner-chains-are-coming-to-cardano/) //! * [Starknet's Madara Sequencer](https://github.com/keep-starknet-strange/madara) +//! * [Polymesh](https://polymesh.network/) //! //! [`substrate`]: crate::polkadot_sdk::substrate //! [`frame`]: crate::polkadot_sdk::frame_runtime //! [`cumulus`]: crate::polkadot_sdk::cumulus //! [`polkadot`]: crate::polkadot_sdk::polkadot //! [`xcm`]: crate::polkadot_sdk::xcm +//! [`frame-omni-bencher`]: https://crates.io/crates/frame-omni-bencher +//! [`polkadot-parachain-bin`]: https://crates.io/crates/polkadot-parachain-bin +//! [`polkadot-omni-node`]: https://crates.io/crates/polkadot-omni-node /// Learn about Cumulus, the framework that transforms [`substrate`]-based chains into /// [`polkadot`]-enabled parachains. diff --git a/docs/sdk/src/polkadot_sdk/substrate.rs b/docs/sdk/src/polkadot_sdk/substrate.rs index 56b89f8c9c2a..ed654c2842c4 100644 --- a/docs/sdk/src/polkadot_sdk/substrate.rs +++ b/docs/sdk/src/polkadot_sdk/substrate.rs @@ -90,22 +90,6 @@ //! //! In order to ensure that the WASM build is **deterministic**, the [Substrate Runtime Toolbox (srtool)](https://github.com/paritytech/srtool) can be used. //! -//! ### Binaries -//! -//! Multiple binaries are shipped with substrate, the most important of which are located in the -//! [`./bin`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin) folder. -//! -//! * [`node_cli`] is an extensive substrate node that contains the superset of all runtime and node -//! side features. The corresponding runtime, called [`kitchensink_runtime`] contains all of the -//! modules that are provided with `FRAME`. This node and runtime is only used for testing and -//! demonstration. -//! * [`chain_spec_builder`]: Utility to build more detailed chain-specs for the aforementioned -//! node. Other projects typically contain a `build-spec` subcommand that does the same. -//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node): -//! a template node that contains a minimal set of features and can act as a starting point of a -//! project. -//! * [`subkey`]: Substrate's key management utility. -//! //! ### Anatomy of a Binary Crate //! //! From the above, [`node_cli`]/[`kitchensink_runtime`] and `node-template` are essentially diff --git a/docs/sdk/src/reference_docs/chain_spec_genesis.rs b/docs/sdk/src/reference_docs/chain_spec_genesis.rs index a2e22d1ed1eb..b7a0a648d0cf 100644 --- a/docs/sdk/src/reference_docs/chain_spec_genesis.rs +++ b/docs/sdk/src/reference_docs/chain_spec_genesis.rs @@ -100,17 +100,22 @@ //! others useful for testing. //! //! Internally, presets can be provided in a number of ways: -//! - JSON in string form: -#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", preset_1)] -//! - JSON using runtime types to serialize values: +//! - using [`build_struct_json_patch`] macro (**recommended**): #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", preset_2)] +//! - JSON using runtime types to serialize values: #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", preset_3)] +//! - JSON in string form: +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", preset_1)] +//! //! It is worth noting that a preset does not have to be the full `RuntimeGenesisConfig`, in that //! sense that it does not have to contain all the keys of the struct. The preset is actually a JSON //! patch that will be merged with the default value of `RuntimeGenesisConfig`. This approach should //! simplify maintenance of built-in presets. The following example illustrates a runtime genesis -//! config patch: +//! config patch with a single key built using [`build_struct_json_patch`] macro: #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", preset_4)] +//! This results in the following JSON blob: +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", preset_4_json)] +//! //! //! ## Note on the importance of testing presets //! @@ -122,8 +127,8 @@ //! //! ## Note on the importance of using the `deny_unknown_fields` attribute //! -//! It is worth noting that it is easy to make a hard-to-spot mistake, as in the following example -//! ([`FooStruct`] does not contain `fieldC`): +//! It is worth noting that when manually building preset JSON blobs it is easy to make a +//! hard-to-spot mistake, as in the following example ([`FooStruct`] does not contain `fieldC`): #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", preset_invalid)] //! Even though `preset_invalid` contains a key that does not exist, the deserialization of the JSON //! blob does not fail. The misspelling is silently ignored due to the lack of the @@ -131,6 +136,10 @@ //! `GenesisConfig`. #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", invalid_preset_works)] //! +//! To avoid this problem [`build_struct_json_patch`] macro shall be used whenever possible (it +//! internally instantiates the struct before serializang it JSON blob, so all unknown fields shall +//! be caught at compilation time). +//! //! ## Runtime `GenesisConfig` raw format //! //! A raw format of genesis config contains just the state's keys and values as they are stored in @@ -152,10 +161,13 @@ //! presets and build the chain specification file. It is possible to use the tool with the //! [_demonstration runtime_][`chain_spec_guide_runtime`]. To build the required packages, just run //! the following command: +//! //! ```ignore //! cargo build -p staging-chain-spec-builder -p chain-spec-guide-runtime --release //! ``` +//! //! The `chain-spec-builder` util can also be installed with `cargo install`: +//! //! ```ignore //! cargo install staging-chain-spec-builder //! cargo build -p chain-spec-guide-runtime --release @@ -179,6 +191,7 @@ //! [`get_preset`]: frame_support::genesis_builder_helper::get_preset //! [`pallet::genesis_build`]: frame_support::pallet_macros::genesis_build //! [`pallet::genesis_config`]: frame_support::pallet_macros::genesis_config +//! [`build_struct_json_patch`]: frame_support::build_struct_json_patch //! [`BuildGenesisConfig`]: frame_support::traits::BuildGenesisConfig //! [`serde`]: https://serde.rs/field-attrs.html //! [`get_storage_for_patch`]: sc_chain_spec::GenesisConfigBuilderRuntimeCaller::get_storage_for_patch 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 028495712032..07c0342f5fbe 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/Cargo.toml @@ -12,6 +12,7 @@ publish = false [dependencies] docify = { workspace = true } codec = { workspace = true } +frame-support = { workspace = true } scale-info = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } @@ -49,6 +50,7 @@ std = [ "codec/std", "scale-info/std", + "frame-support/std", "frame/std", "pallet-balances/std", diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs index 2ff2d9539e2d..571632ecd272 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/pallets.rs @@ -118,7 +118,7 @@ pub mod pallet_foo { pub some_enum: FooEnum, pub some_struct: FooStruct, #[serde(skip)] - _phantom: PhantomData, + pub _phantom: PhantomData, } #[pallet::genesis_build] 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 02c2d90f7c82..5918f2b8ccd5 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 @@ -17,8 +17,12 @@ //! Presets for the chain-spec demo runtime. -use crate::pallets::{FooEnum, SomeFooData1, SomeFooData2}; +use crate::{ + pallets::{FooEnum, SomeFooData1, SomeFooData2}, + runtime::{BarConfig, FooConfig, RuntimeGenesisConfig}, +}; 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; @@ -27,7 +31,7 @@ use sp_keyring::AccountKeyring; pub const PRESET_1: &str = "preset_1"; /// A demo preset with real types. pub const PRESET_2: &str = "preset_2"; -/// Another demo preset with real types. +/// Another demo preset with real types and manually created json object. pub const PRESET_3: &str = "preset_3"; /// A single value patch preset. pub const PRESET_4: &str = "preset_4"; @@ -58,21 +62,21 @@ fn preset_1() -> Value { } #[docify::export] -/// Function provides a preset demonstrating how use the actual types to create a preset. +/// Function provides a preset demonstrating how to create a preset using +/// [`build_struct_json_patch`] macro. fn preset_2() -> Value { - json!({ - "bar": { - "initialAccount": AccountKeyring::Ferdie.public().to_ss58check(), - }, - "foo": { - "someEnum": FooEnum::Data2(SomeFooData2 { values: vec![12,16] }), - "someInteger": 200 + build_struct_json_patch!(RuntimeGenesisConfig { + foo: FooConfig { + some_integer: 200, + some_enum: FooEnum::Data2(SomeFooData2 { values: vec![0x0c, 0x10] }) }, + bar: BarConfig { initial_account: Some(AccountKeyring::Ferdie.public().into()) }, }) } #[docify::export] -/// Function provides a preset demonstrating how use the actual types to create a preset. +/// Function provides a preset demonstrating how use the actual types to manually create a JSON +/// representing the preset. fn preset_3() -> Value { json!({ "bar": { @@ -92,22 +96,16 @@ fn preset_3() -> Value { #[docify::export] /// Function provides a minimal preset demonstrating how to patch single key in -/// `RuntimeGenesisConfig`. -fn preset_4() -> Value { - json!({ - "foo": { - "someEnum": { - "Data2": { - "values": "0x0c0f" - } - }, - }, +/// `RuntimeGenesisConfig` using [`build_struct_json_patch`] macro. +pub fn preset_4() -> Value { + build_struct_json_patch!(RuntimeGenesisConfig { + foo: FooConfig { some_enum: FooEnum::Data2(SomeFooData2 { values: vec![0x0c, 0x10] }) }, }) } #[docify::export] /// Function provides an invalid preset demonstrating how important is use of -/// [`deny_unknown_fields`] in data structures used in `GenesisConfig`. +/// `deny_unknown_fields` in data structures used in `GenesisConfig`. fn preset_invalid() -> Value { json!({ "foo": { @@ -123,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 cc273685fcb4..c2fe5a6727e6 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 @@ -58,7 +58,7 @@ fn get_preset() { let output: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); - //note: copy of chain_spec_guide_runtime::preset_1 + //note: copy of chain_spec_guide_runtime::preset_2 let expected_output = json!({ "bar": { "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", @@ -186,3 +186,20 @@ fn generate_para_chain_spec() { }); assert_eq!(output, expected_output, "Output did not match expected"); } + +#[test] +#[docify::export] +fn preset_4_json() { + assert_eq!( + chain_spec_guide_runtime::presets::preset_4(), + json!({ + "foo": { + "someEnum": { + "Data2": { + "values": "0x0c10" + } + }, + }, + }) + ); +} diff --git a/docs/sdk/src/reference_docs/extrinsic_encoding.rs b/docs/sdk/src/reference_docs/extrinsic_encoding.rs index 31ce92c67e98..1d4b0405b324 100644 --- a/docs/sdk/src/reference_docs/extrinsic_encoding.rs +++ b/docs/sdk/src/reference_docs/extrinsic_encoding.rs @@ -12,7 +12,7 @@ //! //! What follows is a description of how extrinsics based on this //! [`sp_runtime::generic::UncheckedExtrinsic`] type are encoded into bytes. Specifically, we are -//! looking at how extrinsics with a format version of 4 are encoded. This version is itself a part +//! looking at how extrinsics with a format version of 5 are encoded. This version is itself a part //! of the payload, and if it changes, it indicates that something about the encoding may have //! changed. //! @@ -24,7 +24,8 @@ //! ```text //! extrinsic_bytes = concat( //! compact_encoded_length, -//! version_and_maybe_signature, +//! version_and_extrinsic_type, +//! maybe_extension_data, //! call_data //! ) //! ``` @@ -56,18 +57,38 @@ //! version_and_signed, //! from_address, //! signature, -//! signed_extensions_extra, +//! transaction_extensions_extra, //! ) //! ``` //! //! Each of the details to be concatenated together is explained below: //! -//! ### version_and_signed +//! ## version_and_extrinsic_type //! -//! This is one byte, equal to `0x84` or `0b1000_0100` (i.e. an upper 1 bit to denote that it is -//! signed, and then the transaction version, 4, in the lower bits). +//! This byte has 2 components: +//! - the 2 most significant bits represent the extrinsic type: +//! - bare - `0b00` +//! - signed - `0b10` +//! - general - `0b01` +//! - the 6 least significant bits represent the extrinsic format version (currently 5) //! -//! ### from_address +//! ### Bare extrinsics +//! +//! If the extrinsic is _bare_, then `version_and_extrinsic_type` will be just the _transaction +//! protocol version_, which is 5 (or `0b0000_0101`). Bare extrinsics do not carry any other +//! extension data, so `maybe_extension_data` would not be included in the payload and the +//! `version_and_extrinsic_type` would always be followed by the encoded call bytes. +//! +//! ### Signed extrinsics +//! +//! If the extrinsic is _signed_ (all extrinsics submitted from users used to be signed up until +//! version 4), then `version_and_extrinsic_type` is obtained by having a MSB of `1` on the +//! _transaction protocol version_ byte (which translates to `0b1000_0101`). +//! +//! Additionally, _signed_ extrinsics also carry with them address and signature information encoded +//! as follows: +//! +//! #### from_address //! //! This is the [SCALE encoded][frame::deps::codec] address of the sender of the extrinsic. The //! address is the first generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], and so @@ -78,7 +99,7 @@ //! signed extrinsic to be submitted to a Polkadot node, you'll always use the //! [`sp_runtime::MultiAddress::Id`] variant to wrap your `AccountId32`. //! -//! ### signature +//! #### signature //! //! This is the [SCALE encoded][frame::deps::codec] signature. The signature type is configured via //! the third generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], which determines the @@ -90,32 +111,41 @@ //! The signature type used on the Polkadot relay chain is [`sp_runtime::MultiSignature`]; the //! variants there are the types of signature that can be provided. //! -//! ### signed_extensions_extra +//! ### General extrinsics +//! +//! If the extrinsic is _general_ (it doesn't carry a signature in the payload, only extension +//! data), then `version_and_extrinsic_type` is obtained by logical OR between the general +//! transaction type bits and the _transaction protocol version_ byte (which translates to +//! `0b0100_0101`). //! -//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing each of -//! the [_signed extensions_][sp_runtime::traits::SignedExtension], and are configured by the -//! fourth generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about -//! signed extensions [here][crate::reference_docs::signed_extensions]. +//! ### transaction_extensions_extra //! -//! When it comes to constructing an extrinsic, each signed extension has two things that we are -//! interested in here: +//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing first a +//! single byte describing the extension version (this is bumped whenever a change occurs in the +//! transaction extension pipeline) followed by the bytes of each of the [_transaction +//! extensions_][sp_runtime::traits::TransactionExtension], and are configured by the fourth generic +//! parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about transaction +//! extensions [here][crate::reference_docs::transaction_extensions]. //! -//! - The actual SCALE encoding of the signed extension type itself; this is what will form our -//! `signed_extensions_extra` bytes. -//! - An `AdditionalSigned` type. This is SCALE encoded into the `signed_extensions_additional` data -//! of the _signed payload_ (see below). +//! When it comes to constructing an extrinsic, each transaction extension has two things that we +//! are interested in here: +//! +//! - The actual SCALE encoding of the transaction extension type itself; this is what will form our +//! `transaction_extensions_extra` bytes. +//! - An `Implicit` type. This is SCALE encoded into the `transaction_extensions_implicit` data (see +//! below). //! //! Either (or both) of these can encode to zero bytes. //! -//! Each chain configures the set of signed extensions that it uses in its runtime configuration. -//! At the time of writing, Polkadot configures them +//! Each chain configures the set of transaction extensions that it uses in its runtime +//! configuration. At the time of writing, Polkadot configures them //! [here](https://github.com/polkadot-fellows/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/polkadot/src/lib.rs#L1432C25-L1432C25). -//! Some of the common signed extensions are defined -//! [here][frame::deps::frame_system#signed-extensions]. +//! Some of the common transaction extensions are defined +//! [here][frame::deps::frame_system#transaction-extensions]. //! -//! Information about exactly which signed extensions are present on a chain and in what order is -//! also a part of the metadata for the chain. For V15 metadata, it can be -//! [found here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata]. +//! Information about exactly which transaction extensions are present on a chain and in what order +//! is also a part of the metadata for the chain. For V15 metadata, it can be [found +//! here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata]. //! //! ## call_data //! @@ -150,53 +180,63 @@ //! are typically provided as values to the inner enum. //! //! Information about the pallets that exist for a chain (including their indexes), the calls -//! available in each pallet (including their indexes), and the arguments required for each call -//! can be found in the metadata for the chain. For V15 metadata, this information -//! [is here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata]. +//! available in each pallet (including their indexes), and the arguments required for each call can +//! be found in the metadata for the chain. For V15 metadata, this information [is +//! here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata]. //! //! # The Signed Payload Format //! -//! All extrinsics submitted to a node from the outside world (also known as _transactions_) need to -//! be _signed_. The data that needs to be signed for some extrinsic is called the _signed payload_, -//! and its shape is described by the following pseudo-code: +//! All _signed_ extrinsics submitted to a node from the outside world (also known as +//! _transactions_) need to be _signed_. The data that needs to be signed for some extrinsic is +//! called the _signed payload_, and its shape is described by the following pseudo-code: //! //! ```text -//! signed_payload = concat( -//! call_data, -//! signed_extensions_extra, -//! signed_extensions_additional, +//! signed_payload = blake2_256( +//! concat( +//! call_data, +//! transaction_extensions_extra, +//! transaction_extensions_implicit, +//! ) //! ) -//! -//! if length(signed_payload) > 256 { -//! signed_payload = blake2_256(signed_payload) -//! } //! ``` //! -//! The bytes representing `call_data` and `signed_extensions_extra` can be obtained as described -//! above. `signed_extensions_additional` is constructed by SCALE encoding the -//! ["additional signed" data][sp_runtime::traits::SignedExtension::AdditionalSigned] for each -//! signed extension that the chain is using, in order. +//! The bytes representing `call_data` and `transaction_extensions_extra` can be obtained as +//! descibed above. `transaction_extensions_implicit` is constructed by SCALE encoding the +//! ["implicit" data][sp_runtime::traits::TransactionExtension::Implicit] for each transaction +//! extension that the chain is using, in order. +//! +//! Once we've concatenated those together, we hash the result using a Blake2 256bit hasher. +//! +//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload for +//! us, given `call_data` and a tuple of transaction extensions. //! -//! Once we've concatenated those together, we hash the result if it's greater than 256 bytes in -//! length using a Blake2 256bit hasher. +//! # The General Transaction Format //! -//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload -//! for us, given `call_data` and a tuple of signed extensions. +//! A General transaction does not have a signature method hardcoded in the check logic of the +//! extrinsic, such as a traditionally signed transaction. Instead, general transactions should have +//! one or more extensions in the transaction extension pipeline that auhtorize origins in some way, +//! one of which could be the traditional signature check that happens for all signed transactions +//! in the [Checkable](sp_runtime::traits::Checkable) implementation of +//! [UncheckedExtrinsic](sp_runtime::generic::UncheckedExtrinsic). Therefore, it is up to each +//! extension to define the format of the payload it will try to check and authorize the right +//! origin type. For an example, look into the [authorization example pallet +//! extensions](pallet_example_authorization_tx_extension::extensions) //! //! # Example Encoding //! -//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic -//! as follows: +//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic as +//! follows: #![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", encoding_example)] #[docify::export] pub mod call_data { use codec::{Decode, Encode}; + use sp_runtime::{traits::Dispatchable, DispatchResultWithInfo}; // The outer enum composes calls within // different pallets together. We have two // pallets, "PalletA" and "PalletB". - #[derive(Encode, Decode)] + #[derive(Encode, Decode, Clone)] pub enum Call { #[codec(index = 0)] PalletA(PalletACall), @@ -207,23 +247,33 @@ pub mod call_data { // An inner enum represents the calls within // a specific pallet. "PalletA" has one call, // "Foo". - #[derive(Encode, Decode)] + #[derive(Encode, Decode, Clone)] pub enum PalletACall { #[codec(index = 0)] Foo(String), } - #[derive(Encode, Decode)] + #[derive(Encode, Decode, Clone)] pub enum PalletBCall { #[codec(index = 0)] Bar(String), } + + impl Dispatchable for Call { + type RuntimeOrigin = (); + type Config = (); + type Info = (); + type PostInfo = (); + fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo { + Ok(()) + } + } } #[docify::export] pub mod encoding_example { use super::call_data::{Call, PalletACall}; - use crate::reference_docs::signed_extensions::signed_extensions_example; + use crate::reference_docs::transaction_extensions::transaction_extensions_example; use codec::Encode; use sp_core::crypto::AccountId32; use sp_keyring::sr25519::Keyring; @@ -232,34 +282,40 @@ pub mod encoding_example { MultiAddress, MultiSignature, }; - // Define some signed extensions to use. We'll use a couple of examples - // from the signed extensions reference doc. - type SignedExtensions = - (signed_extensions_example::AddToPayload, signed_extensions_example::AddToSignaturePayload); + // Define some transaction extensions to use. We'll use a couple of examples + // from the transaction extensions reference doc. + type TransactionExtensions = ( + transaction_extensions_example::AddToPayload, + transaction_extensions_example::AddToSignaturePayload, + ); // We'll use `UncheckedExtrinsic` to encode our extrinsic for us. We set // the address and signature type to those used on Polkadot, use our custom - // `Call` type, and use our custom set of `SignedExtensions`. - type Extrinsic = - UncheckedExtrinsic, Call, MultiSignature, SignedExtensions>; + // `Call` type, and use our custom set of `TransactionExtensions`. + type Extrinsic = UncheckedExtrinsic< + MultiAddress, + Call, + MultiSignature, + TransactionExtensions, + >; pub fn encode_demo_extrinsic() -> Vec { // The "from" address will be our Alice dev account. let from_address = MultiAddress::::Id(Keyring::Alice.to_account_id()); - // We provide some values for our expected signed extensions. - let signed_extensions = ( - signed_extensions_example::AddToPayload(1), - signed_extensions_example::AddToSignaturePayload, + // We provide some values for our expected transaction extensions. + let transaction_extensions = ( + transaction_extensions_example::AddToPayload(1), + transaction_extensions_example::AddToSignaturePayload, ); // Construct our call data: let call_data = Call::PalletA(PalletACall::Foo("Hello".to_string())); // The signed payload. This takes care of encoding the call_data, - // signed_extensions_extra and signed_extensions_additional, and hashing + // transaction_extensions_extra and transaction_extensions_implicit, and hashing // the result if it's > 256 bytes: - let signed_payload = SignedPayload::new(&call_data, signed_extensions.clone()); + let signed_payload = SignedPayload::new(call_data.clone(), transaction_extensions.clone()); // Sign the signed payload with our Alice dev account's private key, // and wrap the signature into the expected type: @@ -269,7 +325,7 @@ pub mod encoding_example { }; // Now, we can build and encode our extrinsic: - let ext = Extrinsic::new_signed(call_data, from_address, signature, signed_extensions); + let ext = Extrinsic::new_signed(call_data, from_address, signature, transaction_extensions); let encoded_ext = ext.encode(); encoded_ext diff --git a/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs b/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs index cf9e58791492..68d7d31f67f3 100644 --- a/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs +++ b/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs @@ -1,23 +1,212 @@ //! # FRAME Benchmarking and Weights. //! -//! Notes: +//! This reference doc explores the concept of weights within Polkadot-SDK runtimes, and more +//! specifically how FRAME-based runtimes handle it. //! -//! On Weight as a concept. +//! ## Metering //! -//! - Why we need it. Super important. People hate this. We need to argue why it is worth it. -//! - Axis of weight: PoV + Time. -//! - pre dispatch weight vs. metering and post dispatch correction. -//! - mention that we will do this for PoV -//! - you can manually refund using `DispatchResultWithPostInfo`. -//! - Technically you can have weights with any benchmarking framework. You just need one number to -//! be computed pre-dispatch. But FRAME gives you a framework for this. -//! - improve documentation of `#[weight = ..]` and `#[pallet::weight(..)]`. All syntax variation -//! should be covered. +//! The existence of "weight" as a concept in Polkadot-SDK is a direct consequence of the usage of +//! WASM as a virtual machine. Unlike a metered virtual machine like EVM, where every instruction +//! can have a (fairly) deterministic "cost" (also known as "gas price") associated with it, WASM is +//! a stack machine with more complex instruction set, and more unpredictable execution times. This +//! means that unlike EVM, it is not possible to implement a "metering" system in WASM. A metering +//! system is one in which instructions are executed one by one, and the cost/gas is stored in an +//! accumulator. The execution may then halt once a gas limit is reached. //! -//! On FRAME benchmarking machinery: +//! In Polkadot-SDK, the WASM runtime is not assumed to be metered. //! -//! - Component analysis, why everything must be linear. -//! - How to write benchmarks, how you must think of worst case. -//! - How to run benchmarks. +//! ## Trusted Code //! -//! - +//! Another important difference is that EVM is mostly used to express smart contracts, which are +//! foreign and untrusted codes from the perspective of the blockchain executing them. In such +//! cases, metering is crucial, in order to ensure a malicious code cannot consume more gas than +//! expected. +//! +//! This assumption does not hold about the runtime of Polkadot-SDK-based blockchains. The runtime +//! is trusted code, and it is assumed to be written by the same team/developers who are running the +//! blockchain itself. Therefore, this assumption of "untrusted foreign code" does not hold. +//! +//! This is why the runtime can opt for a more performant, more flexible virtual machine like WASM, +//! and get away without having metering. +//! +//! ## Benchmarking +//! +//! With the matter of untrusted code execution out of the way, the need for strict metering goes +//! out of the way. Yet, it would still be very beneficial for block producers to be able to know an +//! upper bound on how much resources a operation is going to consume before actually executing that +//! operation. This is why FRAME has a toolkit for benchmarking pallets: So that this upper bound +//! can be empirically determined. +//! +//! > Note: Benchmarking is a static analysis: It is all about knowing the upper bound of how much +//! > resources an operation takes statically, without actually executing it. In the context of +//! > FRAME extrinsics, this static-ness is expressed by the keyword "pre-dispatch". +//! +//! To understand why this upper bound is needed, consider the following: A block producer knows +//! they have 20ms left to finish producing their block, and wishes to include more transactions in +//! the block. Yet, in a metered environment, it would not know which transaction is likely to fit +//! the 20ms. In a benchmarked environment, it can examine the transactions for their upper bound, +//! and include the ones that are known to fit based on the worst case. +//! +//! The benchmarking code can be written as a part of FRAME pallet, using the macros provided in +//! [`frame_benchmarking`]. See any of the existing pallets in `polkadot-sdk`, or the pallets in our +//! [`crate::polkadot_sdk::templates`] for examples. +//! +//! ## Weight +//! +//! Finally, [`sp_weights::Weight`] is the output of the benchmarking process. It is a +//! two-dimensional data structure that demonstrates the resources consumed by a given block of +//! code (for example, a transaction). The two dimensions are: +//! +//! * reference time: The time consumed in pico-seconds, on a reference hardware. +//! * proof size: The amount of storage proof necessary to re-execute the block of code. This is +//! mainly needed for parachain <> relay-chain verification. +//! +//! ## How To Write Benchmarks: Worst Case +//! +//! The most important detail about writing benchmarking code is that it must be written such that +//! it captures the worst case execution of any block of code. +//! +//! Consider: +#![doc = docify::embed!("./src/reference_docs/frame_benchmarking_weight.rs", simple_transfer)] +//! +//! If this block of code is to be benchmarked, then the benchmarking code must be written such that +//! it captures the worst case. +//! +//! ## Gluing Pallet Benchmarking with Runtime +//! +//! FRAME pallets are mandated to provide their own benchmarking code. Runtimes contain the +//! boilerplate needed to run these benchmarking (see [Running Benchmarks +//! below](#running-benchmarks)). The outcome of running these benchmarks are meant to be fed back +//! into the pallet via a conventional `trait WeightInfo` on `Config`: +#![doc = docify::embed!("src/reference_docs/frame_benchmarking_weight.rs", WeightInfo)] +//! +//! Then, individual functions of this trait are the final values that we assigned to the +//! [`frame::pallet_macros::weight`] attribute: +#![doc = docify::embed!("./src/reference_docs/frame_benchmarking_weight.rs", simple_transfer_2)] +//! +//! ## Manual Refund +//! +//! Back to the assumption of writing benchmarks for worst case: Sometimes, the pre-dispatch weight +//! significantly differ from the post-dispatch actual weight consumed. This can be expressed with +//! the following FRAME syntax: +#![doc = docify::embed!("./src/reference_docs/frame_benchmarking_weight.rs", simple_transfer_3)] +//! +//! ## Running Benchmarks +//! +//! Two ways exist to run the benchmarks of a runtime. +//! +//! 1. The old school way: Most Polkadot-SDK based nodes (such as the ones integrated in +//! [`templates`]) have an a `benchmark` subcommand integrated into themselves. +//! 2. The more [`crate::reference_docs::omni_node`] compatible way of running the benchmarks would +//! be using [`frame-omni-bencher`] CLI, which only relies on a runtime. +//! +//! Note that by convention, the runtime and pallets always have their benchmarking code feature +//! gated as behind `runtime-benchmarks`. So, the runtime should be compiled with `--features +//! runtime-benchmarks`. +//! +//! ## Automatic Refund of `proof_size`. +//! +//! A new feature in FRAME allows the runtime to be configured for "automatic refund" of the proof +//! size weight. This is very useful for maximizing the throughput of parachains. Please see: +//! [`crate::guides::enable_pov_reclaim`]. +//! +//! ## Summary +//! +//! Polkadot-SDK runtimes use a more performant VM, namely WASM, which does not have metering. In +//! return they have to be benchmarked to provide an upper bound on the resources they consume. This +//! upper bound is represented as [`sp_weights::Weight`]. +//! +//! ## Future: PolkaVM +//! +//! With the transition of Polkadot relay chain to [JAM], a set of new features are being +//! introduced, one of which being a new virtual machine named [PolkaVM] that is as flexible as +//! WASM, but also capable of metering. This might alter the future of benchmarking in FRAME and +//! Polkadot-SDK, rendering them not needed anymore once PolkaVM is fully integrated into +//! Polkadot-sdk. For a basic explanation of JAM and PolkaVM, see [here](https://blog.kianenigma.com/posts/tech/demystifying-jam/#pvm). +//! +//! +//! [`frame-omni-bencher`]: https://crates.io/crates/frame-omni-bencher +//! [`templates`]: crate::polkadot_sdk::templates +//! [PolkaVM]: https://github.com/koute/polkavm +//! [JAM]: https://graypaper.com + +#[frame::pallet(dev_mode)] +#[allow(unused_variables, unreachable_code, unused, clippy::diverging_sub_expression)] +pub mod pallet { + use frame::prelude::*; + + #[docify::export] + pub trait WeightInfo { + fn simple_transfer() -> Weight; + } + + #[pallet::config] + pub trait Config: frame_system::Config { + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + #[docify::export] + #[pallet::weight(10_000)] + pub fn simple_transfer( + origin: OriginFor, + destination: T::AccountId, + amount: u32, + ) -> DispatchResult { + let destination_exists = todo!(); + if destination_exists { + // simpler code path + } else { + // more complex code path + } + Ok(()) + } + + #[docify::export] + #[pallet::weight(T::WeightInfo::simple_transfer())] + pub fn simple_transfer_2( + origin: OriginFor, + destination: T::AccountId, + amount: u32, + ) -> DispatchResult { + let destination_exists = todo!(); + if destination_exists { + // simpler code path + } else { + // more complex code path + } + Ok(()) + } + + #[docify::export] + // This is the worst-case, pre-dispatch weight. + #[pallet::weight(T::WeightInfo::simple_transfer())] + pub fn simple_transfer_3( + origin: OriginFor, + destination: T::AccountId, + amount: u32, + ) -> DispatchResultWithPostInfo { + // ^^ Notice the new return type + let destination_exists = todo!(); + if destination_exists { + // simpler code path + // Note that need for .into(), to convert `()` to `PostDispatchInfo` + // See: https://paritytech.github.io/polkadot-sdk/master/frame_support/dispatch/struct.PostDispatchInfo.html#impl-From%3C()%3E-for-PostDispatchInfo + Ok(().into()) + } else { + // more complex code path + let actual_weight = + todo!("this can likely come from another benchmark that is NOT the worst case"); + let pays_fee = todo!("You can set this to `Pays::Yes` or `Pays::No` to change if this transaction should pay fees"); + Ok(frame::deps::frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(actual_weight), + pays_fee, + }) + } + } + } +} diff --git a/docs/sdk/src/reference_docs/frame_runtime_types.rs b/docs/sdk/src/reference_docs/frame_runtime_types.rs index e99106ade878..ec7196cea662 100644 --- a/docs/sdk/src/reference_docs/frame_runtime_types.rs +++ b/docs/sdk/src/reference_docs/frame_runtime_types.rs @@ -134,7 +134,7 @@ //! * [`crate::reference_docs::frame_origin`] explores further details about the usage of //! `RuntimeOrigin`. //! * [`RuntimeCall`] is a particularly interesting composite enum as it dictates the encoding of an -//! extrinsic. See [`crate::reference_docs::signed_extensions`] for more information. +//! extrinsic. See [`crate::reference_docs::transaction_extensions`] for more information. //! * See the documentation of [`construct_runtime`]. //! * See the corresponding lecture in the [pba-book](https://polkadot-blockchain-academy.github.io/pba-book/frame/outer-enum/page.html). //! diff --git a/docs/sdk/src/reference_docs/mod.rs b/docs/sdk/src/reference_docs/mod.rs index 7f2edb08d46e..e47eece784c4 100644 --- a/docs/sdk/src/reference_docs/mod.rs +++ b/docs/sdk/src/reference_docs/mod.rs @@ -40,9 +40,12 @@ pub mod runtime_vs_smart_contract; /// Learn about how extrinsics are encoded to be transmitted to a node and stored in blocks. pub mod extrinsic_encoding; -/// Learn about the signed extensions that form a part of extrinsics. +/// Deprecated in favor of transaction extensions. pub mod signed_extensions; +/// Learn about the transaction extensions that form a part of extrinsics. +pub mod transaction_extensions; + /// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built. pub mod frame_origin; @@ -75,7 +78,6 @@ pub mod frame_system_accounts; pub mod development_environment_advice; /// Learn about benchmarking and weight. -// TODO: @shawntabrizi @ggwpez https://github.com/paritytech/polkadot-sdk-docs/issues/50 pub mod frame_benchmarking_weight; /// Learn about the token-related logic in FRAME and how to apply it to your use case. @@ -106,3 +108,6 @@ pub mod umbrella_crate; /// Learn about how to create custom RPC endpoints and runtime APIs. pub mod custom_runtime_api_rpc; + +/// The [`polkadot-omni-node`](https://crates.io/crates/polkadot-omni-node) and its related binaries. +pub mod omni_node; diff --git a/docs/sdk/src/reference_docs/omni_node.rs b/docs/sdk/src/reference_docs/omni_node.rs new file mode 100644 index 000000000000..44d63704a458 --- /dev/null +++ b/docs/sdk/src/reference_docs/omni_node.rs @@ -0,0 +1,185 @@ +//! # (Omni) Node +//! +//! This reference doc elaborates on what a Polkadot-SDK/Substrate node software is, and what +//! various ways exist to run one. +//! +//! The node software, as denoted in [`crate::reference_docs::wasm_meta_protocol`], is everything in +//! a blockchain other than the WASM runtime. It contains common components such as the database, +//! networking, RPC server and consensus. Substrate-based nodes are native binaries that are +//! compiled down from the Rust source code. The `node` folder in any of the [`templates`] are +//! examples of this source. +//! +//! > Note: A typical node also contains a lot of other tools (exposed as subcommands) that are +//! > useful for operating a blockchain, such as the ones noted in +//! > [`polkadot_omni_node_lib::cli::Cli::subcommand`]. +//! +//! ## Node <> Runtime Interdependence +//! +//! While in principle the node can be mostly independent of the runtime, for various reasons, such +//! as the [native runtime](crate::reference_docs::wasm_meta_protocol#native-runtime), the node and +//! runtime were historically tightly linked together. Another reason is that the node and the +//! runtime need to be in agreement about which consensus algorithm they use, as described +//! [below](#consensus-engine). +//! +//! Specifically, the node relied on the existence of a linked runtime, and *could only reliably run +//! that runtime*. This is why if you look at any of the [`templates`], they are all composed of a +//! node, and a runtime. +//! +//! Moreover, the code and API of each of these nodes was historically very advanced, and tailored +//! towards those who wish to customize many of the node components at depth. +//! +//! > The notorious `service.rs` in any node template is a good example of this. +//! +//! A [trend](https://github.com/paritytech/polkadot-sdk/issues/62) has already been undergoing in +//! order to de-couple the node and the runtime for a long time. The north star of this effort is +//! twofold : +//! +//! 1. develop what can be described as an "omni-node": A node that can run most runtimes. +//! 2. provide a cleaner abstraction for creating a custom node. +//! +//! While a single omni-node running *all possible runtimes* is not feasible, the +//! [`polkadot-omni-node`] is an attempt at creating the former, and the [`polkadot_omni_node_lib`] +//! is the latter. +//! +//! > Note: The OmniNodes are mainly focused on the development needs of **Polkadot +//! > parachains ONLY**, not (Substrate) solo-chains. For the time being, solo-chains are not +//! > supported by the OmniNodes. This might change in the future. +//! +//! ## Types of Nodes +//! +//! With the emergence of the OmniNodes, let's look at the various Node options available to a +//! builder. +//! +//! ### [`polkadot-omni-node`] +//! +//! [`polkadot-omni-node`] is a white-labeled binary, released as a part of Polkadot SDK that is +//! capable of meeting the needs of most Polkadot parachains. +//! +//! It can act as the collator of a parachain in production, with all the related auxillary +//! functionalities that a normal collator node has: RPC server, archiving state, etc. Moreover, it +//! can also run the wasm blob of the parachain locally for testing and development. +//! +//! ### [`polkadot_omni_node_lib`] +//! +//! [`polkadot_omni_node_lib`] is the library version of the above, which can be used to create a +//! fresh parachain node, with a some limited configuration options using a lean API. +//! +//! ### Old School Nodes +//! +//! The existing node architecture, as seen in the [`templates`], is still available for those who +//! want to have full control over the node software. +//! +//! ### Summary +//! +//! We can summarize the choices for the node software of any given user of Polkadot-SDK, wishing to +//! deploy a parachain into 3 categories: +//! +//! 1. **Use the [`polkadot-omni-node`]**: This is the easiest way to get started, and is the most +//! likely to be the best choice for most users. +//! * can run almost any runtime with [`--dev-block-time`] +//! 2. **Use the [`polkadot_omni_node_lib`]**: This is the best choice for those who want to have +//! slightly more control over the node software, such as embedding a custom chain-spec. +//! 3. **Use the old school nodes**: This is the best choice for those who want to have full control +//! over the node software, such as changing the consensus engine, altering the transaction pool, +//! and so on. +//! +//! ## _OmniTools_: User Journey +//! +//! All in all, the user journey of a team/builder, in the OmniNode world is as follows: +//! +//! * The [`templates`], most notably the [`parachain-template`] is the canonical starting point. +//! That being said, the node code of the templates (which may be eventually +//! removed/feature-gated) is no longer of relevance. The only focus is in the runtime, and +//! obtaining a `.wasm` file. References: +//! * [`crate::guides::your_first_pallet`] +//! * [`crate::guides::your_first_runtime`] +//! * If need be, the weights of the runtime need to be updated using `frame-omni-bencher`. +//! References: +//! * [`crate::reference_docs::frame_benchmarking_weight`] +//! * Next, [`chain-spec-builder`] is used to generate a `chain_spec.json`, either for development, +//! or for production. References: +//! * [`crate::reference_docs::chain_spec_genesis`] +//! * For local development, the following options are available: +//! * `polkadot-omni-node` (notably, with [`--dev-block-time`]). References: +//! * [`crate::guides::your_first_node`] +//! * External tools such as `chopsticks`, `zombienet`. +//! * See the `README.md` file of the `polkadot-sdk-parachain-template`. +//! * For production `polkadot-omni-node` can be used out of the box. +//! * For further customization [`polkadot_omni_node_lib`] can be used. +//! +//! ## Appendix +//! +//! This section describes how the interdependence between the node and the runtime is related to +//! the consensus engine. This information is useful for those who want to understand the +//! historical context of the node and the runtime. +//! +//! ### Consensus Engine +//! +//! In any given substrate-based chain, both the node and the runtime will have their own +//! opinion/information about what consensus engine is going to be used. +//! +//! In practice, the majority of the implementation of any consensus engine is in the node side, but +//! the runtime also typically needs to expose a custom runtime-api to enable the particular +//! consensus engine to work, and that particular runtime-api is implemented by a pallet +//! corresponding to that consensus engine. +//! +//! For example, taking a snippet from [`solochain_template_runtime`], the runtime has to provide +//! this additional runtime-api (compared to [`minimal_template_runtime`]), if the node software is +//! configured to use the Aura consensus engine: +//! +//! ```text +//! impl sp_consensus_aura::AuraApi for Runtime { +//! fn slot_duration() -> sp_consensus_aura::SlotDuration { +//! ... +//! } +//! fn authorities() -> Vec { +//! ... +//! } +//! } +//! ``` +//! +//! For simplicity, we can break down "consensus" into two main parts: +//! +//! * Block Authoring: Deciding who gets to produce the next block. +//! * Finality: Deciding when a block is considered final. +//! +//! For block authoring, there are a number of options: +//! +//! * [`sc_consensus_manual_seal`]: Useful for testing, where any node can produce a block at any +//! time. This is often combined with a fixed interval at which a block is produced. +//! * [`sc_consensus_aura`]/[`pallet_aura`]: A simple round-robin block authoring mechanism. +//! * [`sc_consensus_babe`]/[`pallet_babe`]: A more advanced block authoring mechanism, capable of +//! anonymizing the next block author. +//! * [`sc_consensus_pow`]: Proof of Work block authoring. +//! +//! For finality, there is one main option shipped with polkadot-sdk: +//! +//! * [`sc_consensus_grandpa`]/[`pallet_grandpa`]: A finality gadget that uses a voting mechanism to +//! decide when a block +//! +//! **The most important lesson here is that the node and the runtime must have matching consensus +//! components.** +//! +//! ### Consequences for OmniNode +//! +//! +//! The consequence of the above is that anyone using the OmniNode must also be aware of the +//! consensus system used in the runtime, and be aware if it is matching that of the OmniNode or +//! not. For the time being, [`polkadot-omni-node`] only supports: +//! +//! * Parachain-based Aura consensus, with 6s async-backing block-time, and before full elastic +//! scaling). [`polkadot_omni_node_lib::cli::Cli::experimental_use_slot_based`] for fixed factor +//! scaling (a step +//! * Ability to run any runtime with [`--dev-block-time`] flag. This uses +//! [`sc_consensus_manual_seal`] under the hood, and has no restrictions on the runtime's +//! consensus. +//! +//! [This](https://github.com/paritytech/polkadot-sdk/issues/5565) future improvement to OmniNode +//! aims to make such checks automatic. +//! +//! +//! [`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 diff --git a/docs/sdk/src/reference_docs/signed_extensions.rs b/docs/sdk/src/reference_docs/signed_extensions.rs index c644aeaa4165..6e44fea88ded 100644 --- a/docs/sdk/src/reference_docs/signed_extensions.rs +++ b/docs/sdk/src/reference_docs/signed_extensions.rs @@ -1,131 +1,2 @@ -//! Signed extensions are, briefly, a means for different chains to extend the "basic" extrinsic -//! format with custom data that can be checked by the runtime. -//! -//! # FRAME provided signed extensions -//! -//! FRAME by default already provides the following signed extensions: -//! -//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same -//! network. Determined based on genesis. -//! -//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable -//! mortality. -//! -//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a -//! transaction is not the *all zero account* (all bytes of the accountid are zero). -//! -//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay -//! of transactions and to provide ordering of transactions. -//! -//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for -//! the currently active runtime. -//! -//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the -//! correct encoding of the call. -//! -//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block -//! before dispatching it. -//! -//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges -//! transaction fees from the signer based on the weight of the call using the native token. -//! -//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction -//! fees from the signer based on the weight of the call using any supported asset (including the -//! native token). -//! -//! - [`ChargeAssetTxPayment`(using -//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction -//! fees from the signer based on the weight of the call using any supported asset (including the -//! native token). The asset is converted to the native token using a pool. -//! -//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions -//! to be processed without paying any fee. This requires that the `call` that should be -//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if) -//! attribute. -//! -//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions -//! to include the so-called metadata hash. This is required by chains to support the generic -//! Ledger application and other similar offline wallets. -//! -//! - [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim): A -//! signed extension for parachains that reclaims unused storage weight after executing a -//! transaction. -//! -//! For more information about these extensions, follow the link to the type documentation. -//! -//! # Building a custom signed extension -//! -//! Defining a couple of very simple signed extensions looks like the following: -#![doc = docify::embed!("./src/reference_docs/signed_extensions.rs", signed_extensions_example)] - -#[docify::export] -pub mod signed_extensions_example { - use codec::{Decode, Encode}; - use scale_info::TypeInfo; - use sp_runtime::traits::SignedExtension; - - // This doesn't actually check anything, but simply allows - // some arbitrary `u32` to be added to the extrinsic payload - #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] - pub struct AddToPayload(pub u32); - - impl SignedExtension for AddToPayload { - const IDENTIFIER: &'static str = "AddToPayload"; - type AccountId = (); - type Call = (); - type AdditionalSigned = (); - type Pre = (); - - fn additional_signed( - &self, - ) -> Result< - Self::AdditionalSigned, - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(()) - } - - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } - } - - // This is the opposite; nothing will be added to the extrinsic payload, - // but the AdditionalSigned type (`1234u32`) will be added to the - // payload to be signed. - #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] - pub struct AddToSignaturePayload; - - impl SignedExtension for AddToSignaturePayload { - const IDENTIFIER: &'static str = "AddToSignaturePayload"; - type AccountId = (); - type Call = (); - type AdditionalSigned = u32; - type Pre = (); - - fn additional_signed( - &self, - ) -> Result< - Self::AdditionalSigned, - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(1234) - } - - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } - } -} +//! `SignedExtension`s are deprecated in favor of +//! [`TransactionExtension`s](crate::reference_docs::transaction_extensions). diff --git a/docs/sdk/src/reference_docs/transaction_extensions.rs b/docs/sdk/src/reference_docs/transaction_extensions.rs new file mode 100644 index 000000000000..0f8198e8372d --- /dev/null +++ b/docs/sdk/src/reference_docs/transaction_extensions.rs @@ -0,0 +1,103 @@ +//! Transaction extensions are, briefly, a means for different chains to extend the "basic" +//! extrinsic format with custom data that can be checked by the runtime. +//! +//! # FRAME provided transaction extensions +//! +//! FRAME by default already provides the following transaction extensions: +//! +//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same +//! network. Determined based on genesis. +//! +//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable +//! mortality. +//! +//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a +//! transaction is not the *all zero account* (all bytes of the accountid are zero). +//! +//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay +//! of transactions and to provide ordering of transactions. +//! +//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for +//! the currently active runtime. +//! +//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the +//! correct encoding of the call. +//! +//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block +//! before dispatching it. +//! +//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges +//! transaction fees from the signer based on the weight of the call using the native token. +//! +//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction +//! fees from the signer based on the weight of the call using any supported asset (including the +//! native token). +//! +//! - [`ChargeAssetTxPayment`(using +//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction +//! fees from the signer based on the weight of the call using any supported asset (including the +//! native token). The asset is converted to the native token using a pool. +//! +//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions +//! to be processed without paying any fee. This requires that the `call` that should be +//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if) +//! attribute. +//! +//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions +//! to include the so-called metadata hash. This is required by chains to support the generic +//! Ledger application and other similar offline wallets. +//! +//! - [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim): A +//! transaction extension for parachains that reclaims unused storage weight after executing a +//! transaction. +//! +//! For more information about these extensions, follow the link to the type documentation. +//! +//! # Building a custom transaction extension +//! +//! Defining a couple of very simple transaction extensions looks like the following: +#![doc = docify::embed!("./src/reference_docs/transaction_extensions.rs", transaction_extensions_example)] + +#[docify::export] +pub mod transaction_extensions_example { + use codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::{ + impl_tx_ext_default, + traits::{Dispatchable, TransactionExtension}, + transaction_validity::TransactionValidityError, + }; + + // This doesn't actually check anything, but simply allows + // some arbitrary `u32` to be added to the extrinsic payload + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToPayload(pub u32); + + impl TransactionExtension for AddToPayload { + const IDENTIFIER: &'static str = "AddToPayload"; + type Implicit = (); + type Pre = (); + type Val = (); + + impl_tx_ext_default!(Call; weight validate prepare); + } + + // This is the opposite; nothing will be added to the extrinsic payload, + // but the Implicit type (`1234u32`) will be added to the + // payload to be signed. + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToSignaturePayload; + + impl TransactionExtension for AddToSignaturePayload { + const IDENTIFIER: &'static str = "AddToSignaturePayload"; + type Implicit = u32; + + fn implicit(&self) -> Result { + Ok(1234) + } + type Pre = (); + type Val = (); + + impl_tx_ext_default!(Call; weight validate prepare); + } +} diff --git a/docs/sdk/src/reference_docs/umbrella_crate.rs b/docs/sdk/src/reference_docs/umbrella_crate.rs index 1074cde37693..8d9bcdfc2089 100644 --- a/docs/sdk/src/reference_docs/umbrella_crate.rs +++ b/docs/sdk/src/reference_docs/umbrella_crate.rs @@ -5,6 +5,7 @@ //! crate. This helps with selecting the right combination of crate versions, since otherwise 3rd //! party tools are needed to select a compatible set of versions. //! +//! //! ## Features //! //! The umbrella crate supports no-std builds and can therefore be used in the runtime and node. 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/cli/src/command.rs b/polkadot/cli/src/command.rs index d124c8fb7eb7..02c9b97150c2 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -15,12 +15,14 @@ // along with Polkadot. If not, see . use crate::cli::{Cli, Subcommand, NODE_VERSION}; -use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; +use frame_benchmarking_cli::{ + BenchmarkCmd, ExtrinsicFactory, SubstrateRemarkBuilder, SUBSTRATE_REFERENCE_HARDWARE, +}; use futures::future::TryFutureExt; use log::info; use polkadot_service::{ self, - benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder}, + benchmarking::{benchmark_inherent_data, TransferKeepAliveBuilder}, HeaderBackend, IdentifyVariant, }; #[cfg(feature = "pyroscope")] @@ -203,10 +205,12 @@ where runner.run_node_until_exit(move |config| async move { let hwbench = (!cli.run.no_hardware_benchmarks) - .then_some(config.database.path().map(|database_path| { - let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) - })) + .then(|| { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(&database_path); + sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) + }) + }) .flatten(); let database_source = config.database.clone(); @@ -389,44 +393,40 @@ pub fn run() -> Result<()> { cmd.run(client.clone()).map_err(Error::SubstrateCli) }), - // These commands are very similar and can be handled in nearly the same way. - BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => - runner.sync_run(|mut config| { - let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config)?; - let header = client.header(client.info().genesis_hash).unwrap().unwrap(); - let inherent_data = benchmark_inherent_data(header) - .map_err(|e| format!("generating inherent data: {:?}", e))?; - let remark_builder = - RemarkBuilder::new(client.clone(), config.chain_spec.identify_chain()); - - match cmd { - BenchmarkCmd::Extrinsic(cmd) => { - let tka_builder = TransferKeepAliveBuilder::new( - client.clone(), - Sr25519Keyring::Alice.to_account_id(), - config.chain_spec.identify_chain(), - ); - - let ext_factory = ExtrinsicFactory(vec![ - Box::new(remark_builder), - Box::new(tka_builder), - ]); - - cmd.run(client.clone(), inherent_data, Vec::new(), &ext_factory) - .map_err(Error::SubstrateCli) - }, - BenchmarkCmd::Overhead(cmd) => cmd - .run( - config, - client.clone(), - inherent_data, - Vec::new(), - &remark_builder, - ) - .map_err(Error::SubstrateCli), - _ => unreachable!("Ensured by the outside match; qed"), - } - }), + BenchmarkCmd::Overhead(cmd) => runner.sync_run(|config| { + if cmd.params.runtime.is_some() { + return Err(sc_cli::Error::Input( + "Polkadot binary does not support `--runtime` flag for `benchmark overhead`. Please provide a chain spec or use the `frame-omni-bencher`." + .into(), + ) + .into()) + } + + cmd.run_with_default_builder_and_spec::( + Some(config.chain_spec), + ) + .map_err(Error::SubstrateCli) + }), + BenchmarkCmd::Extrinsic(cmd) => runner.sync_run(|mut config| { + let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config)?; + let header = client.header(client.info().genesis_hash).unwrap().unwrap(); + let inherent_data = benchmark_inherent_data(header) + .map_err(|e| format!("generating inherent data: {:?}", e))?; + + let remark_builder = SubstrateRemarkBuilder::new_from_client(client.clone())?; + + let tka_builder = TransferKeepAliveBuilder::new( + client.clone(), + Sr25519Keyring::Alice.to_account_id(), + config.chain_spec.identify_chain(), + ); + + let ext_factory = + ExtrinsicFactory(vec![Box::new(remark_builder), Box::new(tka_builder)]); + + cmd.run(client.clone(), inherent_data, Vec::new(), &ext_factory) + .map_err(Error::SubstrateCli) + }), BenchmarkCmd::Pallet(cmd) => { set_default_ss58_version(chain_spec); diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index 4b0a5f7248ab..777458673f5b 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -21,6 +21,7 @@ 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] polkadot-node-subsystem-test-helpers = { workspace = true } @@ -28,3 +29,4 @@ 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 f04e3c4f20b4..2599026080df 100644 --- a/polkadot/node/collation-generation/src/error.rs +++ b/polkadot/node/collation-generation/src/error.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use polkadot_primitives::vstaging::CommittedCandidateReceiptError; use thiserror::Error; #[derive(Debug, Error)] @@ -30,8 +31,12 @@ pub enum Error { UtilRuntime(#[from] polkadot_node_subsystem_util::runtime::Error), #[error(transparent)] Erasure(#[from] polkadot_erasure_coding::Error), - #[error("Parachain backing state not available in runtime.")] - MissingParaBackingState, + #[error("Collation submitted before initialization")] + SubmittedBeforeInit, + #[error("V2 core index check failed: {0}")] + CandidateReceiptCheck(CommittedCandidateReceiptError), + #[error("PoV size {0} exceeded maximum size of {1}")] + POVSizeExceeded(usize, usize), } pub type Result = std::result::Result; diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 50adbddea413..b371017a8289 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -32,26 +32,34 @@ #![deny(missing_docs)] use codec::Encode; -use futures::{channel::oneshot, future::FutureExt, join, select}; +use error::{Error, Result}; +use futures::{channel::oneshot, future::FutureExt, select}; use polkadot_node_primitives::{ AvailableData, Collation, CollationGenerationConfig, CollationSecondedSignal, PoV, SubmitCollationParams, }; use polkadot_node_subsystem::{ - messages::{CollationGenerationMessage, CollatorProtocolMessage}, - overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, SpawnedSubsystem, - SubsystemContext, SubsystemError, SubsystemResult, + messages::{CollationGenerationMessage, CollatorProtocolMessage, RuntimeApiMessage}, + overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, + SubsystemContext, SubsystemError, SubsystemResult, SubsystemSender, }; use polkadot_node_subsystem_util::{ - request_async_backing_params, request_availability_cores, request_para_backing_state, - request_persisted_validation_data, request_validation_code, request_validation_code_hash, - request_validators, runtime::fetch_claim_queue, + request_claim_queue, request_persisted_validation_data, request_session_index_for_child, + request_validation_code_hash, request_validators, + runtime::{request_node_features, ClaimQueueSnapshot}, }; use polkadot_primitives::{ - collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, - CollatorPair, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ScheduledCore, ValidationCodeHash, + collator_signature_payload, + node_features::FeatureIndex, + vstaging::{ + transpose_claim_queue, CandidateDescriptorV2, CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2, TransposedClaimQueue, + }, + CandidateCommitments, CandidateDescriptor, CollatorPair, CoreIndex, Hash, Id as ParaId, + NodeFeatures, OccupiedCoreAssumption, PersistedValidationData, SessionIndex, + ValidationCodeHash, }; +use schnellru::{ByLength, LruMap}; use sp_core::crypto::Pair; use std::sync::Arc; @@ -68,6 +76,7 @@ const LOG_TARGET: &'static str = "parachain::collation-generation"; /// Collation Generation Subsystem pub struct CollationGenerationSubsystem { config: Option>, + session_info_cache: SessionInfoCache, metrics: Metrics, } @@ -75,7 +84,7 @@ pub struct CollationGenerationSubsystem { impl CollationGenerationSubsystem { /// Create a new instance of the `CollationGenerationSubsystem`. pub fn new(metrics: Metrics) -> Self { - Self { config: None, metrics } + Self { config: None, metrics, session_info_cache: SessionInfoCache::new() } } /// Run this subsystem @@ -116,19 +125,8 @@ impl CollationGenerationSubsystem { activated, .. }))) => { - // follow the procedure from the guide - if let Some(config) = &self.config { - let metrics = self.metrics.clone(); - if let Err(err) = handle_new_activations( - config.clone(), - activated.into_iter().map(|v| v.hash), - ctx, - metrics, - ) - .await - { - gum::warn!(target: LOG_TARGET, err = ?err, "failed to handle new activations"); - } + if let Err(err) = self.handle_new_activation(activated.map(|v| v.hash), ctx).await { + gum::warn!(target: LOG_TARGET, err = ?err, "failed to handle new activation"); } false @@ -153,14 +151,8 @@ impl CollationGenerationSubsystem { Ok(FromOrchestra::Communication { msg: CollationGenerationMessage::SubmitCollation(params), }) => { - if let Some(config) = &self.config { - if let Err(err) = - handle_submit_collation(params, config, ctx, &self.metrics).await - { - gum::error!(target: LOG_TARGET, ?err, "Failed to submit collation"); - } - } else { - gum::error!(target: LOG_TARGET, "Collation submitted before initialization"); + if let Err(err) = self.handle_submit_collation(params, ctx).await { + gum::error!(target: LOG_TARGET, ?err, "Failed to submit collation"); } false @@ -177,175 +169,132 @@ impl CollationGenerationSubsystem { }, } } -} - -#[overseer::subsystem(CollationGeneration, error=SubsystemError, prefix=self::overseer)] -impl CollationGenerationSubsystem { - fn start(self, ctx: Context) -> SpawnedSubsystem { - let future = async move { - self.run(ctx).await; - Ok(()) - } - .boxed(); - - SpawnedSubsystem { name: "collation-generation-subsystem", future } - } -} -#[overseer::contextbounds(CollationGeneration, prefix = self::overseer)] -async fn handle_new_activations( - config: Arc, - activated: impl IntoIterator, - ctx: &mut Context, - metrics: Metrics, -) -> crate::error::Result<()> { - // follow the procedure from the guide: - // https://paritytech.github.io/polkadot-sdk/book/node/collators/collation-generation.html - - // If there is no collation function provided, bail out early. - // Important: Lookahead collator and slot based collator do not use `CollatorFn`. - if config.collator.is_none() { - return Ok(()) - } - - let para_id = config.para_id; - - let _overall_timer = metrics.time_new_activations(); - - for relay_parent in activated { - let _relay_parent_timer = metrics.time_new_activations_relay_parent(); - - let (availability_cores, validators, async_backing_params) = join!( - request_availability_cores(relay_parent, ctx.sender()).await, - request_validators(relay_parent, ctx.sender()).await, - request_async_backing_params(relay_parent, ctx.sender()).await, - ); - - let availability_cores = availability_cores??; - let async_backing_params = async_backing_params?.ok(); - let n_validators = validators??.len(); - let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent) - .await - .map_err(crate::error::Error::UtilRuntime)?; - - // The loop bellow will fill in cores that the para is allowed to build on. - let mut cores_to_build_on = Vec::new(); - - // This assumption refers to all cores of the parachain, taking elastic scaling - // into account. - let mut para_assumption = None; - for (core_idx, core) in availability_cores.into_iter().enumerate() { - // This nested assumption refers only to the core being iterated. - let (core_assumption, scheduled_core) = match core { - CoreState::Scheduled(scheduled_core) => - (OccupiedCoreAssumption::Free, scheduled_core), - CoreState::Occupied(occupied_core) => match async_backing_params { - Some(params) if params.max_candidate_depth >= 1 => { - // maximum candidate depth when building on top of a block - // pending availability is necessarily 1 - the depth of the - // pending block is 0 so the child has depth 1. - - // Use claim queue if available, or fallback to `next_up_on_available` - let res = match maybe_claim_queue { - Some(ref claim_queue) => { - // read what's in the claim queue for this core at depth 0. - claim_queue - .get_claim_for(CoreIndex(core_idx as u32), 0) - .map(|para_id| ScheduledCore { para_id, collator: None }) - }, - None => { - // Runtime doesn't support claim queue runtime api. Fallback to - // `next_up_on_available` - occupied_core.next_up_on_available - }, - }; + async fn handle_submit_collation( + &mut self, + params: SubmitCollationParams, + ctx: &mut Context, + ) -> Result<()> { + let Some(config) = &self.config else { + return Err(Error::SubmittedBeforeInit); + }; + let _timer = self.metrics.time_submit_collation(); - match res { - Some(res) => (OccupiedCoreAssumption::Included, res), - None => continue, - } - }, - _ => { - gum::trace!( - target: LOG_TARGET, - core_idx = %core_idx, - relay_parent = ?relay_parent, - "core is occupied. Keep going.", - ); - continue - }, - }, - CoreState::Free => { - gum::trace!( - target: LOG_TARGET, - core_idx = %core_idx, - "core is not assigned to any para. Keep going.", - ); - continue - }, - }; + let SubmitCollationParams { + relay_parent, + collation, + parent_head, + validation_code_hash, + result_sender, + core_index, + } = params; - if scheduled_core.para_id != config.para_id { - gum::trace!( + let mut validation_data = match request_persisted_validation_data( + relay_parent, + config.para_id, + OccupiedCoreAssumption::TimedOut, + ctx.sender(), + ) + .await + .await?? + { + Some(v) => v, + None => { + gum::debug!( target: LOG_TARGET, - core_idx = %core_idx, relay_parent = ?relay_parent, our_para = %config.para_id, - their_para = %scheduled_core.para_id, - "core is not assigned to our para. Keep going.", + "No validation data for para - does it exist at this relay-parent?", ); - } else { - // This does not work for elastic scaling, but it should be enough for single - // core parachains. If async backing runtime is available we later override - // the assumption based on the `para_backing_state` API response. - para_assumption = Some(core_assumption); - // Accumulate cores for building collation(s) outside the loop. - cores_to_build_on.push(CoreIndex(core_idx as u32)); - } - } + return Ok(()) + }, + }; - // Skip to next relay parent if there is no core assigned to us. - if cores_to_build_on.is_empty() { - continue + // We need to swap the parent-head data, but all other fields here will be correct. + validation_data.parent_head = parent_head; + + let claim_queue = request_claim_queue(relay_parent, ctx.sender()).await.await??; + + let session_index = + request_session_index_for_child(relay_parent, ctx.sender()).await.await??; + + let session_info = + self.session_info_cache.get(relay_parent, session_index, ctx.sender()).await?; + let collation = PreparedCollation { + collation, + relay_parent, + para_id: config.para_id, + validation_data, + validation_code_hash, + n_validators: session_info.n_validators, + core_index, + session_index, + }; + + construct_and_distribute_receipt( + collation, + config.key.clone(), + ctx.sender(), + result_sender, + &mut self.metrics, + session_info.v2_receipts, + &transpose_claim_queue(claim_queue), + ) + .await?; + + Ok(()) + } + + async fn handle_new_activation( + &mut self, + maybe_activated: Option, + ctx: &mut Context, + ) -> Result<()> { + let Some(config) = &self.config else { + return Ok(()); + }; + + let Some(relay_parent) = maybe_activated else { return Ok(()) }; + + // If there is no collation function provided, bail out early. + // Important: Lookahead collator and slot based collator do not use `CollatorFn`. + if config.collator.is_none() { + return Ok(()) } - // If at least one core is assigned to us, `para_assumption` is `Some`. - let Some(mut para_assumption) = para_assumption else { continue }; - - // If it is none it means that neither async backing or elastic scaling (which - // depends on it) are supported. We'll use the `para_assumption` we got from - // iterating cores. - if async_backing_params.is_some() { - // We are being very optimistic here, but one of the cores could pend availability some - // more block, ore even time out. - // For timeout assumption the collator can't really know because it doesn't receive - // bitfield gossip. - let para_backing_state = - request_para_backing_state(relay_parent, config.para_id, ctx.sender()) - .await - .await?? - .ok_or(crate::error::Error::MissingParaBackingState)?; - - // Override the assumption about the para's assigned cores. - para_assumption = if para_backing_state.pending_availability.is_empty() { - OccupiedCoreAssumption::Free - } else { - OccupiedCoreAssumption::Included - } + let para_id = config.para_id; + + let _timer = self.metrics.time_new_activation(); + + let session_index = + request_session_index_for_child(relay_parent, ctx.sender()).await.await??; + + let session_info = + self.session_info_cache.get(relay_parent, session_index, ctx.sender()).await?; + let n_validators = session_info.n_validators; + + let claim_queue = + ClaimQueueSnapshot::from(request_claim_queue(relay_parent, ctx.sender()).await.await??); + + let cores_to_build_on = claim_queue + .iter_claims_at_depth(0) + .filter_map(|(core_idx, para_id)| (para_id == config.para_id).then_some(core_idx)) + .collect::>(); + + // Nothing to do if no core assigned to us. + if cores_to_build_on.is_empty() { + return Ok(()) } - gum::debug!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - our_para = %para_id, - ?para_assumption, - "Occupied core(s) assumption", - ); + // We are being very optimistic here, but one of the cores could be pending availability + // for some more blocks, or even time out. We assume all cores are being freed. let mut validation_data = match request_persisted_validation_data( relay_parent, para_id, - para_assumption, + // Just use included assumption always. If there are no pending candidates it's a + // no-op. + OccupiedCoreAssumption::Included, ctx.sender(), ) .await @@ -359,17 +308,20 @@ async fn handle_new_activations( our_para = %para_id, "validation data is not available", ); - continue + return Ok(()) }, }; - let validation_code_hash = match obtain_validation_code_hash_with_assumption( + let validation_code_hash = match request_validation_code_hash( relay_parent, para_id, - para_assumption, + // Just use included assumption always. If there are no pending candidates it's a + // no-op. + OccupiedCoreAssumption::Included, ctx.sender(), ) - .await? + .await + .await?? { Some(v) => v, None => { @@ -379,17 +331,19 @@ async fn handle_new_activations( our_para = %para_id, "validation code hash is not found.", ); - continue + return Ok(()) }, }; let task_config = config.clone(); - let metrics = metrics.clone(); + let metrics = self.metrics.clone(); let mut task_sender = ctx.sender().clone(); ctx.spawn( "chained-collation-builder", Box::pin(async move { + let transposed_claim_queue = transpose_claim_queue(claim_queue.0); + for core_index in cores_to_build_on { let collator_fn = match task_config.collator.as_ref() { Some(x) => x, @@ -410,7 +364,7 @@ async fn handle_new_activations( }; let parent_head = collation.head_data.clone(); - construct_and_distribute_receipt( + if let Err(err) = construct_and_distribute_receipt( PreparedCollation { collation, para_id, @@ -419,13 +373,24 @@ async fn handle_new_activations( validation_code_hash, n_validators, core_index, + session_index, }, task_config.key.clone(), &mut task_sender, result_sender, &metrics, + session_info.v2_receipts, + &transposed_claim_queue, ) - .await; + .await + { + gum::error!( + target: LOG_TARGET, + "Failed to construct and distribute collation: {}", + err + ); + return + } // Chain the collations. All else stays the same as we build the chained // collation on same relay parent. @@ -433,76 +398,64 @@ async fn handle_new_activations( } }), )?; - } - Ok(()) + Ok(()) + } } -#[overseer::contextbounds(CollationGeneration, prefix = self::overseer)] -async fn handle_submit_collation( - params: SubmitCollationParams, - config: &CollationGenerationConfig, - ctx: &mut Context, - metrics: &Metrics, -) -> crate::error::Result<()> { - let _timer = metrics.time_submit_collation(); +#[overseer::subsystem(CollationGeneration, error=SubsystemError, prefix=self::overseer)] +impl CollationGenerationSubsystem { + fn start(self, ctx: Context) -> SpawnedSubsystem { + let future = async move { + self.run(ctx).await; + Ok(()) + } + .boxed(); - let SubmitCollationParams { - relay_parent, - collation, - parent_head, - validation_code_hash, - result_sender, - core_index, - } = params; + SpawnedSubsystem { name: "collation-generation-subsystem", future } + } +} - let validators = request_validators(relay_parent, ctx.sender()).await.await??; - let n_validators = validators.len(); +#[derive(Clone)] +struct PerSessionInfo { + v2_receipts: bool, + n_validators: usize, +} - // We need to swap the parent-head data, but all other fields here will be correct. - let mut validation_data = match request_persisted_validation_data( - relay_parent, - config.para_id, - OccupiedCoreAssumption::TimedOut, - ctx.sender(), - ) - .await - .await?? - { - Some(v) => v, - None => { - gum::debug!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - our_para = %config.para_id, - "No validation data for para - does it exist at this relay-parent?", - ); - return Ok(()) - }, - }; +struct SessionInfoCache(LruMap); - validation_data.parent_head = parent_head; +impl SessionInfoCache { + fn new() -> Self { + Self(LruMap::new(ByLength::new(2))) + } - let collation = PreparedCollation { - collation, - relay_parent, - para_id: config.para_id, - validation_data, - validation_code_hash, - n_validators, - core_index, - }; + async fn get>( + &mut self, + relay_parent: Hash, + session_index: SessionIndex, + sender: &mut Sender, + ) -> Result { + if let Some(info) = self.0.get(&session_index) { + return Ok(info.clone()) + } - construct_and_distribute_receipt( - collation, - config.key.clone(), - ctx.sender(), - result_sender, - metrics, - ) - .await; + let n_validators = + request_validators(relay_parent, &mut sender.clone()).await.await??.len(); - Ok(()) + let node_features = request_node_features(relay_parent, session_index, sender) + .await? + .unwrap_or(NodeFeatures::EMPTY); + + let info = PerSessionInfo { + v2_receipts: node_features + .get(FeatureIndex::CandidateReceiptV2 as usize) + .map(|b| *b) + .unwrap_or(false), + n_validators, + }; + self.0.insert(session_index, info); + Ok(self.0.get(&session_index).expect("Just inserted").clone()) + } } struct PreparedCollation { @@ -513,6 +466,7 @@ struct PreparedCollation { validation_code_hash: ValidationCodeHash, n_validators: usize, core_index: CoreIndex, + session_index: SessionIndex, } /// Takes a prepared collation, along with its context, and produces a candidate receipt @@ -523,7 +477,9 @@ async fn construct_and_distribute_receipt( sender: &mut impl overseer::CollationGenerationSenderTrait, result_sender: Option>, metrics: &Metrics, -) { + v2_receipts: bool, + transposed_claim_queue: &TransposedClaimQueue, +) -> Result<()> { let PreparedCollation { collation, para_id, @@ -532,6 +488,7 @@ async fn construct_and_distribute_receipt( validation_code_hash, n_validators, core_index, + session_index, } = collation; let persisted_validation_data_hash = validation_data.hash(); @@ -549,15 +506,7 @@ async fn construct_and_distribute_receipt( // As such, honest collators never produce an uncompressed PoV which starts with // a compression magic number, which would lead validators to reject the collation. if encoded_size > validation_data.max_pov_size as usize { - gum::debug!( - target: LOG_TARGET, - para_id = %para_id, - size = encoded_size, - max_size = validation_data.max_pov_size, - "PoV exceeded maximum size" - ); - - return + return Err(Error::POVSizeExceeded(encoded_size, validation_data.max_pov_size as usize)) } pov @@ -573,18 +522,7 @@ async fn construct_and_distribute_receipt( &validation_code_hash, ); - let erasure_root = match erasure_root(n_validators, validation_data, pov.clone()) { - Ok(erasure_root) => erasure_root, - Err(err) => { - gum::error!( - target: LOG_TARGET, - para_id = %para_id, - err = ?err, - "failed to calculate erasure root", - ); - return - }, - }; + let erasure_root = erasure_root(n_validators, validation_data, pov.clone())?; let commitments = CandidateCommitments { upward_messages: collation.upward_messages, @@ -595,34 +533,67 @@ async fn construct_and_distribute_receipt( hrmp_watermark: collation.hrmp_watermark, }; - let ccr = CandidateReceipt { - commitments_hash: commitments.hash(), - descriptor: CandidateDescriptor { - signature: key.sign(&signature_payload), - para_id, - relay_parent, - collator: key.public(), - persisted_validation_data_hash, - pov_hash, - erasure_root, - para_head: commitments.head_data.hash(), - validation_code_hash, - }, + let receipt = if v2_receipts { + let ccr = CommittedCandidateReceiptV2 { + descriptor: CandidateDescriptorV2::new( + para_id, + relay_parent, + core_index, + session_index, + persisted_validation_data_hash, + pov_hash, + erasure_root, + commitments.head_data.hash(), + validation_code_hash, + ), + commitments, + }; + + ccr.check_core_index(&transposed_claim_queue) + .map_err(Error::CandidateReceiptCheck)?; + + ccr.to_plain() + } else { + if commitments.core_selector().map_err(Error::CandidateReceiptCheck)?.is_some() { + gum::warn!( + target: LOG_TARGET, + ?pov_hash, + ?relay_parent, + para_id = %para_id, + "Candidate commitments contain UMP signal without v2 receipts being enabled.", + ); + } + CandidateReceipt { + commitments_hash: commitments.hash(), + descriptor: CandidateDescriptor { + signature: key.sign(&signature_payload), + para_id, + relay_parent, + collator: key.public(), + persisted_validation_data_hash, + pov_hash, + erasure_root, + para_head: commitments.head_data.hash(), + validation_code_hash, + } + .into(), + } }; gum::debug!( target: LOG_TARGET, - candidate_hash = ?ccr.hash(), + candidate_hash = ?receipt.hash(), ?pov_hash, ?relay_parent, para_id = %para_id, + ?core_index, "candidate is generated", ); metrics.on_collation_generated(); sender .send_message(CollatorProtocolMessage::DistributeCollation { - candidate_receipt: ccr, + candidate_receipt: receipt, parent_head_data_hash, pov, parent_head_data, @@ -630,40 +601,15 @@ async fn construct_and_distribute_receipt( core_index, }) .await; -} -async fn obtain_validation_code_hash_with_assumption( - relay_parent: Hash, - para_id: ParaId, - assumption: OccupiedCoreAssumption, - sender: &mut impl overseer::CollationGenerationSenderTrait, -) -> crate::error::Result> { - match request_validation_code_hash(relay_parent, para_id, assumption, sender) - .await - .await? - { - Ok(Some(v)) => Ok(Some(v)), - Ok(None) => Ok(None), - Err(RuntimeApiError::NotSupported { .. }) => { - match request_validation_code(relay_parent, para_id, assumption, sender).await.await? { - Ok(Some(v)) => Ok(Some(v.hash())), - Ok(None) => Ok(None), - Err(e) => { - // We assume that the `validation_code` API is always available, so any error - // is unexpected. - Err(e.into()) - }, - } - }, - Err(e @ RuntimeApiError::Execution { .. }) => Err(e.into()), - } + Ok(()) } fn erasure_root( n_validators: usize, persisted_validation: PersistedValidationData, pov: PoV, -) -> crate::error::Result { +) -> Result { let available_data = AvailableData { validation_data: persisted_validation, pov: Arc::new(pov) }; diff --git a/polkadot/node/collation-generation/src/metrics.rs b/polkadot/node/collation-generation/src/metrics.rs index c7690ec82c4f..80566dcd6fa1 100644 --- a/polkadot/node/collation-generation/src/metrics.rs +++ b/polkadot/node/collation-generation/src/metrics.rs @@ -19,9 +19,7 @@ use polkadot_node_subsystem_util::metrics::{self, prometheus}; #[derive(Clone)] pub(crate) struct MetricsInner { pub(crate) collations_generated_total: prometheus::Counter, - pub(crate) new_activations_overall: prometheus::Histogram, - pub(crate) new_activations_per_relay_parent: prometheus::Histogram, - pub(crate) new_activations_per_availability_core: prometheus::Histogram, + pub(crate) new_activation: prometheus::Histogram, pub(crate) submit_collation: prometheus::Histogram, } @@ -37,26 +35,8 @@ impl Metrics { } /// Provide a timer for new activations which updates on drop. - pub fn time_new_activations(&self) -> Option { - self.0.as_ref().map(|metrics| metrics.new_activations_overall.start_timer()) - } - - /// Provide a timer per relay parents which updates on drop. - pub fn time_new_activations_relay_parent( - &self, - ) -> Option { - self.0 - .as_ref() - .map(|metrics| metrics.new_activations_per_relay_parent.start_timer()) - } - - /// Provide a timer per availability core which updates on drop. - pub fn time_new_activations_availability_core( - &self, - ) -> Option { - self.0 - .as_ref() - .map(|metrics| metrics.new_activations_per_availability_core.start_timer()) + pub fn time_new_activation(&self) -> Option { + self.0.as_ref().map(|metrics| metrics.new_activation.start_timer()) } /// Provide a timer for submitting a collation which updates on drop. @@ -71,44 +51,22 @@ impl metrics::Metrics for Metrics { collations_generated_total: prometheus::register( prometheus::Counter::new( "polkadot_parachain_collations_generated_total", - "Number of collations generated." - )?, - registry, - )?, - new_activations_overall: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collation_generation_new_activations", - "Time spent within fn handle_new_activations", - ) - )?, - registry, - )?, - new_activations_per_relay_parent: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collation_generation_per_relay_parent", - "Time spent handling a particular relay parent within fn handle_new_activations" - ) + "Number of collations generated.", )?, registry, )?, - new_activations_per_availability_core: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collation_generation_per_availability_core", - "Time spent handling a particular availability core for a relay parent in fn handle_new_activations", - ) - )?, + new_activation: prometheus::register( + prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( + "polkadot_parachain_collation_generation_new_activations", + "Time spent within fn handle_new_activation", + ))?, registry, )?, submit_collation: prometheus::register( - prometheus::Histogram::with_opts( - prometheus::HistogramOpts::new( - "polkadot_parachain_collation_generation_submit_collation", - "Time spent preparing and submitting a collation to the network protocol", - ) - )?, + prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( + "polkadot_parachain_collation_generation_submit_collation", + "Time spent preparing and submitting a collation to the network protocol", + ))?, registry, )?, }; diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 7f76988bb035..f81c14cdf8f9 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -17,26 +17,20 @@ use super::*; use assert_matches::assert_matches; use futures::{ - lock::Mutex, task::{Context as FuturesContext, Poll}, - Future, + Future, StreamExt, }; use polkadot_node_primitives::{BlockData, Collation, CollationResult, MaybeCompressedPoV, PoV}; use polkadot_node_subsystem::{ - errors::RuntimeApiError, messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}, ActivatedLeaf, }; -use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; +use polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ - async_backing::{BackingState, CandidatePendingAvailability}, - AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData, - ScheduledCore, ValidationCode, -}; -use polkadot_primitives_test_helpers::{ - dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator, make_candidate, + node_features, vstaging::CandidateDescriptorVersion, CollatorPair, PersistedValidationData, }; +use polkadot_primitives_test_helpers::dummy_head_data; use rstest::rstest; use sp_keyring::sr25519::Keyring as Sr25519Keyring; use std::{ @@ -63,7 +57,7 @@ fn test_harness>(test: impl FnOnce(VirtualOv async move { let mut virtual_overseer = test_fut.await; // Ensure we have handled all responses. - if let Ok(Some(msg)) = virtual_overseer.rx.try_next() { + if let Some(msg) = virtual_overseer.rx.next().timeout(TIMEOUT).await { panic!("Did not handle all responses: {:?}", msg); } // Conclude. @@ -85,20 +79,6 @@ fn test_collation() -> Collation { } } -fn test_collation_compressed() -> Collation { - let mut collation = test_collation(); - let compressed = collation.proof_of_validity.clone().into_compressed(); - collation.proof_of_validity = MaybeCompressedPoV::Compressed(compressed); - collation -} - -fn test_validation_data() -> PersistedValidationData { - let mut persisted_validation_data = PersistedValidationData::default(); - persisted_validation_data.max_pov_size = 1024; - persisted_validation_data -} - -// Box + Unpin + Send struct TestCollator; impl Future for TestCollator { @@ -137,531 +117,11 @@ fn test_config_no_collator>(para_id: Id) -> CollationGeneration } } -fn scheduled_core_for>(para_id: Id) -> ScheduledCore { - ScheduledCore { para_id: para_id.into(), collator: None } -} - -fn dummy_candidate_pending_availability( - para_id: ParaId, - candidate_relay_parent: Hash, - relay_parent_number: BlockNumber, -) -> CandidatePendingAvailability { - let (candidate, _pvd) = make_candidate( - candidate_relay_parent, - relay_parent_number, - para_id, - dummy_head_data(), - HeadData(vec![1]), - ValidationCode(vec![1, 2, 3]).hash(), - ); - let candidate_hash = candidate.hash(); - - CandidatePendingAvailability { - candidate_hash, - descriptor: candidate.descriptor, - commitments: candidate.commitments, - relay_parent_number, - max_pov_size: 5 * 1024 * 1024, - } -} - -fn dummy_backing_state(pending_availability: Vec) -> BackingState { - let constraints = helpers::dummy_constraints( - 0, - vec![0], - dummy_head_data(), - ValidationCodeHash::from(Hash::repeat_byte(42)), - ); - - BackingState { constraints, pending_availability } -} - -#[rstest] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] -fn requests_availability_per_relay_parent(#[case] runtime_version: u32) { - let activated_hashes: Vec = - vec![[1; 32].into(), [4; 32].into(), [9; 32].into(), [16; 32].into()]; - - let requested_availability_cores = Arc::new(Mutex::new(Vec::new())); - - let overseer_requested_availability_cores = requested_availability_cores.clone(); - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::AvailabilityCores(tx)))) => { - overseer_requested_availability_cores.lock().await.push(hash); - tx.send(Ok(vec![])).unwrap(); - } - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request(_hash, RuntimeApiRequest::Validators(tx)))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - } - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::AsyncBackingParams( - tx, - ), - ))) => { - tx.send(Err(RuntimeApiError::NotSupported { runtime_api_name: "doesnt_matter" })).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Version(tx), - ))) => { - tx.send(Ok(runtime_version)).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ClaimQueue(tx), - ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - tx.send(Ok(BTreeMap::new())).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ParaBackingState(_para_id, tx), - ))) => { - tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); - }, - Some(msg) => panic!("didn't expect any other overseer requests given no availability cores; got {:?}", msg), - } - } - }; - - let subsystem_activated_hashes = activated_hashes.clone(); - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations( - Arc::new(test_config(123u32)), - subsystem_activated_hashes, - &mut ctx, - Metrics(None), - ) - .await - .unwrap(); - }); - - let mut requested_availability_cores = Arc::try_unwrap(requested_availability_cores) - .expect("overseer should have shut down by now") - .into_inner(); - requested_availability_cores.sort(); - - assert_eq!(requested_availability_cores, activated_hashes); -} - -#[rstest] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] -fn requests_validation_data_for_scheduled_matches(#[case] runtime_version: u32) { - let activated_hashes: Vec = vec![ - Hash::repeat_byte(1), - Hash::repeat_byte(4), - Hash::repeat_byte(9), - Hash::repeat_byte(16), - ]; - - let requested_validation_data = Arc::new(Mutex::new(Vec::new())); - - let overseer_requested_validation_data = requested_validation_data.clone(); - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AvailabilityCores(tx), - ))) => { - tx.send(Ok(vec![ - CoreState::Free, - // this is weird, see explanation below - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 4) as u32, - )), - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 5) as u32, - )), - ])) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::PersistedValidationData( - _para_id, - _occupied_core_assumption, - tx, - ), - ))) => { - overseer_requested_validation_data.lock().await.push(hash); - tx.send(Ok(None)).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Validators(tx), - ))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::AsyncBackingParams(tx), - ))) => { - tx.send(Err(RuntimeApiError::NotSupported { - runtime_api_name: "doesnt_matter", - })) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Version(tx), - ))) => { - tx.send(Ok(runtime_version)).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ClaimQueue(tx), - ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - tx.send(Ok(BTreeMap::new())).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ParaBackingState(_para_id, tx), - ))) => { - tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); - }, - Some(msg) => { - panic!("didn't expect any other overseer requests; got {:?}", msg) - }, - } - } - }; - - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations( - Arc::new(test_config(16)), - activated_hashes, - &mut ctx, - Metrics(None), - ) - .await - .unwrap(); - }); - - let requested_validation_data = Arc::try_unwrap(requested_validation_data) - .expect("overseer should have shut down by now") - .into_inner(); - - // the only activated hash should be from the 4 hash: - // each activated hash generates two scheduled cores: one with its value * 4, one with its value - // * 5 given that the test configuration has a `para_id` of 16, there's only one way to get that - // value: with the 4 hash. - assert_eq!(requested_validation_data, vec![[4; 32].into()]); -} - -#[rstest] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] -fn sends_distribute_collation_message(#[case] runtime_version: u32) { - let activated_hashes: Vec = vec![ - Hash::repeat_byte(1), - Hash::repeat_byte(4), - Hash::repeat_byte(9), - Hash::repeat_byte(16), - ]; - - // empty vec doesn't allocate on the heap, so it's ok we throw it away - let to_collator_protocol = Arc::new(Mutex::new(Vec::new())); - let inner_to_collator_protocol = to_collator_protocol.clone(); - - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AvailabilityCores(tx), - ))) => { - tx.send(Ok(vec![ - CoreState::Free, - // this is weird, see explanation below - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 4) as u32, - )), - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 5) as u32, - )), - ])) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::PersistedValidationData( - _para_id, - _occupied_core_assumption, - tx, - ), - ))) => { - tx.send(Ok(Some(test_validation_data()))).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Validators(tx), - ))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ValidationCodeHash( - _para_id, - OccupiedCoreAssumption::Free, - tx, - ), - ))) => { - tx.send(Ok(Some(ValidationCode(vec![1, 2, 3]).hash()))).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::AsyncBackingParams(tx), - ))) => { - tx.send(Err(RuntimeApiError::NotSupported { - runtime_api_name: "doesnt_matter", - })) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Version(tx), - ))) => { - tx.send(Ok(runtime_version)).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ClaimQueue(tx), - ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - tx.send(Ok(BTreeMap::new())).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ParaBackingState(_para_id, tx), - ))) => { - tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); - }, - Some(msg @ AllMessages::CollatorProtocol(_)) => { - inner_to_collator_protocol.lock().await.push(msg); - }, - Some(msg) => { - panic!("didn't expect any other overseer requests; got {:?}", msg) - }, - } - } - }; - - let config = Arc::new(test_config(16)); - let subsystem_config = config.clone(); - - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations(subsystem_config, activated_hashes, &mut ctx, Metrics(None)) - .await - .unwrap(); - }); - - let mut to_collator_protocol = Arc::try_unwrap(to_collator_protocol) - .expect("subsystem should have shut down by now") - .into_inner(); - - // we expect a single message to be sent, containing a candidate receipt. - // we don't care too much about the `commitments_hash` right now, but let's ensure that we've - // calculated the correct descriptor - let expect_pov_hash = test_collation_compressed().proof_of_validity.into_compressed().hash(); - let expect_validation_data_hash = test_validation_data().hash(); - let expect_relay_parent = Hash::repeat_byte(4); - let expect_validation_code_hash = ValidationCode(vec![1, 2, 3]).hash(); - let expect_payload = collator_signature_payload( - &expect_relay_parent, - &config.para_id, - &expect_validation_data_hash, - &expect_pov_hash, - &expect_validation_code_hash, - ); - let expect_descriptor = CandidateDescriptor { - signature: config.key.sign(&expect_payload), - para_id: config.para_id, - relay_parent: expect_relay_parent, - collator: config.key.public(), - persisted_validation_data_hash: expect_validation_data_hash, - pov_hash: expect_pov_hash, - erasure_root: dummy_hash(), // this isn't something we're checking right now - para_head: test_collation().head_data.hash(), - validation_code_hash: expect_validation_code_hash, - }; - - assert_eq!(to_collator_protocol.len(), 1); - match AllMessages::from(to_collator_protocol.pop().unwrap()) { - AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { - candidate_receipt, - .. - }) => { - let CandidateReceipt { descriptor, .. } = candidate_receipt; - // signature generation is non-deterministic, so we can't just assert that the - // expected descriptor is correct. What we can do is validate that the produced - // descriptor has a valid signature, then just copy in the generated signature - // and check the rest of the fields for equality. - assert!(CollatorPair::verify( - &descriptor.signature, - &collator_signature_payload( - &descriptor.relay_parent, - &descriptor.para_id, - &descriptor.persisted_validation_data_hash, - &descriptor.pov_hash, - &descriptor.validation_code_hash, - ) - .as_ref(), - &descriptor.collator, - )); - let expect_descriptor = { - let mut expect_descriptor = expect_descriptor; - expect_descriptor.signature = descriptor.signature.clone(); - expect_descriptor.erasure_root = descriptor.erasure_root; - expect_descriptor - }; - assert_eq!(descriptor, expect_descriptor); - }, - _ => panic!("received wrong message type"), - } -} - -#[rstest] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] -fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { - // This is a variant of the above test, but with the validation code hash API disabled. - - let activated_hashes: Vec = vec![ - Hash::repeat_byte(1), - Hash::repeat_byte(4), - Hash::repeat_byte(9), - Hash::repeat_byte(16), - ]; - - // empty vec doesn't allocate on the heap, so it's ok we throw it away - let to_collator_protocol = Arc::new(Mutex::new(Vec::new())); - let inner_to_collator_protocol = to_collator_protocol.clone(); - - let overseer = |mut handle: TestSubsystemContextHandle| async move { - loop { - match handle.try_recv().await { - None => break, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AvailabilityCores(tx), - ))) => { - tx.send(Ok(vec![ - CoreState::Free, - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 4) as u32, - )), - CoreState::Scheduled(scheduled_core_for( - (hash.as_fixed_bytes()[0] * 5) as u32, - )), - ])) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::PersistedValidationData( - _para_id, - _occupied_core_assumption, - tx, - ), - ))) => { - tx.send(Ok(Some(test_validation_data()))).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Validators(tx), - ))) => { - tx.send(Ok(vec![dummy_validator(); 3])).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ValidationCodeHash( - _para_id, - OccupiedCoreAssumption::Free, - tx, - ), - ))) => { - tx.send(Err(RuntimeApiError::NotSupported { - runtime_api_name: "validation_code_hash", - })) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ValidationCode(_para_id, OccupiedCoreAssumption::Free, tx), - ))) => { - tx.send(Ok(Some(ValidationCode(vec![1, 2, 3])))).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::AsyncBackingParams(tx), - ))) => { - tx.send(Err(RuntimeApiError::NotSupported { - runtime_api_name: "doesnt_matter", - })) - .unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::Version(tx), - ))) => { - tx.send(Ok(runtime_version)).unwrap(); - }, - Some(msg @ AllMessages::CollatorProtocol(_)) => { - inner_to_collator_protocol.lock().await.push(msg); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ClaimQueue(tx), - ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - tx.send(Ok(Default::default())).unwrap(); - }, - Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _hash, - RuntimeApiRequest::ParaBackingState(_para_id, tx), - ))) => { - tx.send(Ok(Some(dummy_backing_state(vec![])))).unwrap(); - }, - Some(msg) => { - panic!("didn't expect any other overseer requests; got {:?}", msg) - }, - } - } - }; - - let config = Arc::new(test_config(16u32)); - let subsystem_config = config.clone(); - - // empty vec doesn't allocate on the heap, so it's ok we throw it away - subsystem_test_harness(overseer, |mut ctx| async move { - handle_new_activations(subsystem_config, activated_hashes, &mut ctx, Metrics(None)) - .await - .unwrap(); - }); - - let to_collator_protocol = Arc::try_unwrap(to_collator_protocol) - .expect("subsystem should have shut down by now") - .into_inner(); - - let expect_validation_code_hash = ValidationCode(vec![1, 2, 3]).hash(); - - assert_eq!(to_collator_protocol.len(), 1); - match &to_collator_protocol[0] { - AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { - candidate_receipt, - .. - }) => { - let CandidateReceipt { descriptor, .. } = candidate_receipt; - assert_eq!(expect_validation_code_hash, descriptor.validation_code_hash); - }, - _ => panic!("received wrong message type"), - } +fn node_features_with_v2_enabled() -> NodeFeatures { + let mut node_features = NodeFeatures::new(); + node_features.resize(node_features::FeatureIndex::CandidateReceiptV2 as usize + 1, false); + node_features.set(node_features::FeatureIndex::CandidateReceiptV2 as u8 as usize, true); + node_features } #[test] @@ -717,31 +177,15 @@ fn submit_collation_leads_to_distribution() { }) .await; - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::Validators(tx))) => { - assert_eq!(rp, relay_parent); - let _ = tx.send(Ok(vec![ - Sr25519Keyring::Alice.public().into(), - Sr25519Keyring::Bob.public().into(), - Sr25519Keyring::Charlie.public().into(), - ])); - } - ); - - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { - assert_eq!(rp, relay_parent); - assert_eq!(id, para_id); - assert_eq!(a, OccupiedCoreAssumption::TimedOut); - - // Candidate receipt should be constructed with the real parent head. - let mut pvd = expected_pvd.clone(); - pvd.parent_head = vec![4, 5, 6].into(); - let _ = tx.send(Ok(Some(pvd))); - } - ); + helpers::handle_runtime_calls_on_submit_collation( + &mut virtual_overseer, + relay_parent, + para_id, + expected_pvd.clone(), + NodeFeatures::EMPTY, + Default::default(), + ) + .await; assert_matches!( overseer_recv(&mut virtual_overseer).await, @@ -752,9 +196,9 @@ fn submit_collation_leads_to_distribution() { }) => { let CandidateReceipt { descriptor, .. } = candidate_receipt; assert_eq!(parent_head_data_hash, parent_head.hash()); - assert_eq!(descriptor.persisted_validation_data_hash, expected_pvd.hash()); - assert_eq!(descriptor.para_head, dummy_head_data().hash()); - assert_eq!(descriptor.validation_code_hash, validation_code_hash); + assert_eq!(descriptor.persisted_validation_data_hash(), expected_pvd.hash()); + assert_eq!(descriptor.para_head(), dummy_head_data().hash()); + assert_eq!(descriptor.validation_code_hash(), validation_code_hash); } ); @@ -762,77 +206,16 @@ fn submit_collation_leads_to_distribution() { }); } -// There is one core in `Occupied` state and async backing is enabled. On new head activation -// `CollationGeneration` should produce and distribute a new collation. -#[rstest] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] -fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] runtime_version: u32) { - let activated_hash: Hash = [1; 32].into(); - let para_id = ParaId::from(5); - - // One core, in occupied state. The data in `CoreState` and `ClaimQueue` should match. - let cores: Vec = vec![CoreState::Occupied(polkadot_primitives::OccupiedCore { - next_up_on_available: Some(ScheduledCore { para_id, collator: None }), - occupied_since: 1, - time_out_at: 10, - next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }), - availability: Default::default(), // doesn't matter - group_responsible: polkadot_primitives::GroupIndex(0), - candidate_hash: Default::default(), - candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), - })]; - let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]).into(); - - test_harness(|mut virtual_overseer| async move { - helpers::initialize_collator(&mut virtual_overseer, para_id).await; - helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; - - let pending_availability = - vec![dummy_candidate_pending_availability(para_id, activated_hash, 1)]; - helpers::handle_runtime_calls_on_new_head_activation( - &mut virtual_overseer, - activated_hash, - AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, - cores, - runtime_version, - claim_queue, - ) - .await; - helpers::handle_cores_processing_for_a_leaf( - &mut virtual_overseer, - activated_hash, - para_id, - // `CoreState` is `Occupied` => `OccupiedCoreAssumption` is `Included` - OccupiedCoreAssumption::Included, - 1, - pending_availability, - runtime_version, - ) - .await; - - virtual_overseer - }); -} - #[test] -fn distribute_collation_for_occupied_core_pre_async_backing() { +fn distribute_collation_only_for_assigned_para_id_at_offset_0() { let activated_hash: Hash = [1; 32].into(); let para_id = ParaId::from(5); - let total_cores = 3; - - // Use runtime version before async backing - let runtime_version = RuntimeApiRequest::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT - 1; - let cores = (0..total_cores) + let claim_queue = (0..=5) .into_iter() - .map(|_idx| CoreState::Scheduled(ScheduledCore { para_id, collator: None })) - .collect::>(); - - let claim_queue = cores - .iter() - .enumerate() - .map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id]))) + // Set all cores assigned to para_id 5 at the second and third depths. This shouldn't + // matter. + .map(|idx| (CoreIndex(idx), VecDeque::from([ParaId::from(idx), para_id, para_id]))) .collect::>(); test_harness(|mut virtual_overseer| async move { @@ -841,10 +224,8 @@ fn distribute_collation_for_occupied_core_pre_async_backing() { helpers::handle_runtime_calls_on_new_head_activation( &mut virtual_overseer, activated_hash, - AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, - cores, - runtime_version, claim_queue, + NodeFeatures::EMPTY, ) .await; @@ -852,11 +233,7 @@ fn distribute_collation_for_occupied_core_pre_async_backing() { &mut virtual_overseer, activated_hash, para_id, - // `CoreState` is `Free` => `OccupiedCoreAssumption` is `Free` - OccupiedCoreAssumption::Free, - total_cores, - vec![], - runtime_version, + vec![5], // Only core 5 is assigned to paraid 5. ) .await; @@ -864,48 +241,22 @@ fn distribute_collation_for_occupied_core_pre_async_backing() { }); } -// There are variable number of cores of cores in `Occupied` state and async backing is enabled. -// On new head activation `CollationGeneration` should produce and distribute a new collation -// with proper assumption about the para candidate chain availability at next block. +// There are variable number of cores assigned to the paraid. +// On new head activation `CollationGeneration` should produce and distribute the right number of +// new collations with proper assumption about the para candidate chain availability at next block. #[rstest] #[case(0)] #[case(1)] #[case(2)] -fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elastic_scaling( - #[case] candidates_pending_avail: u32, -) { +#[case(3)] +fn distribute_collation_with_elastic_scaling(#[case] total_cores: u32) { let activated_hash: Hash = [1; 32].into(); let para_id = ParaId::from(5); - // Using latest runtime with the fancy claim queue exposed. - let runtime_version = RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT; - let cores = (0..3) + let claim_queue = (0..total_cores) .into_iter() - .map(|idx| { - CoreState::Occupied(polkadot_primitives::OccupiedCore { - next_up_on_available: Some(ScheduledCore { para_id, collator: None }), - occupied_since: 0, - time_out_at: 10, - next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }), - availability: Default::default(), // doesn't matter - group_responsible: polkadot_primitives::GroupIndex(idx as u32), - candidate_hash: Default::default(), - candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), - }) - }) - .collect::>(); - - let pending_availability = (0..candidates_pending_avail) - .into_iter() - .map(|_idx| dummy_candidate_pending_availability(para_id, activated_hash, 0)) - .collect::>(); - - let claim_queue = cores - .iter() - .enumerate() - .map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id]))) + .map(|idx| (CoreIndex(idx), VecDeque::from([para_id]))) .collect::>(); - let total_cores = cores.len(); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -913,10 +264,8 @@ fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elasti helpers::handle_runtime_calls_on_new_head_activation( &mut virtual_overseer, activated_hash, - AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, - cores, - runtime_version, claim_queue, + NodeFeatures::EMPTY, ) .await; @@ -924,16 +273,7 @@ fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elasti &mut virtual_overseer, activated_hash, para_id, - // if at least 1 cores is occupied => `OccupiedCoreAssumption` is `Included` - // else assumption is `Free`. - if candidates_pending_avail > 0 { - OccupiedCoreAssumption::Included - } else { - OccupiedCoreAssumption::Free - }, - total_cores, - pending_availability, - runtime_version, + (0..total_cores).collect(), ) .await; @@ -941,135 +281,128 @@ fn distribute_collation_for_occupied_cores_with_async_backing_enabled_and_elasti }); } -// There are variable number of cores of cores in `Free` state and async backing is enabled. -// On new head activation `CollationGeneration` should produce and distribute a new collation -// with proper assumption about the para candidate chain availability at next block. #[rstest] -#[case(0)] -#[case(1)] -#[case(2)] -fn distribute_collation_for_free_cores_with_async_backing_enabled_and_elastic_scaling( - #[case] total_cores: usize, -) { - let activated_hash: Hash = [1; 32].into(); +#[case(true)] +#[case(false)] +fn test_candidate_receipt_versioning(#[case] v2_receipts: bool) { + let relay_parent = Hash::repeat_byte(0); + let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); + let parent_head = dummy_head_data(); let para_id = ParaId::from(5); - // Using latest runtime with the fancy claim queue exposed. - let runtime_version = RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT; - - let cores = (0..total_cores) - .into_iter() - .map(|_idx| CoreState::Scheduled(ScheduledCore { para_id, collator: None })) - .collect::>(); - - let claim_queue = cores - .iter() - .enumerate() - .map(|(idx, _core)| (CoreIndex::from(idx as u32), VecDeque::from([para_id]))) - .collect::>(); + let expected_pvd = PersistedValidationData { + parent_head: parent_head.clone(), + relay_parent_number: 10, + relay_parent_storage_root: Hash::repeat_byte(1), + max_pov_size: 1024, + }; + let node_features = + if v2_receipts { node_features_with_v2_enabled() } else { NodeFeatures::EMPTY }; + let expected_descriptor_version = + if v2_receipts { CandidateDescriptorVersion::V2 } else { CandidateDescriptorVersion::V1 }; test_harness(|mut virtual_overseer| async move { - helpers::initialize_collator(&mut virtual_overseer, para_id).await; - helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; - helpers::handle_runtime_calls_on_new_head_activation( - &mut virtual_overseer, - activated_hash, - AsyncBackingParams { max_candidate_depth: 1, allowed_ancestry_len: 1 }, - cores, - runtime_version, - claim_queue, - ) - .await; + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::Initialize(test_config_no_collator(para_id)), + }) + .await; - helpers::handle_cores_processing_for_a_leaf( + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::SubmitCollation(SubmitCollationParams { + relay_parent, + collation: test_collation(), + parent_head: dummy_head_data(), + validation_code_hash, + result_sender: None, + core_index: CoreIndex(0), + }), + }) + .await; + + helpers::handle_runtime_calls_on_submit_collation( &mut virtual_overseer, - activated_hash, + relay_parent, para_id, - // `CoreState` is `Free` => `OccupiedCoreAssumption` is `Free` - OccupiedCoreAssumption::Free, - total_cores, - vec![], - runtime_version, + expected_pvd.clone(), + node_features, + [(CoreIndex(0), [para_id].into_iter().collect())].into_iter().collect(), ) .await; + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation { + candidate_receipt, + parent_head_data_hash, + .. + }) => { + let CandidateReceipt { descriptor, .. } = candidate_receipt; + assert_eq!(parent_head_data_hash, parent_head.hash()); + assert_eq!(descriptor.persisted_validation_data_hash(), expected_pvd.hash()); + assert_eq!(descriptor.para_head(), dummy_head_data().hash()); + assert_eq!(descriptor.validation_code_hash(), validation_code_hash); + // Check that the right version was indeed used. + assert_eq!(descriptor.version(), expected_descriptor_version); + } + ); + virtual_overseer }); } -// There is one core in `Occupied` state and async backing is disabled. On new head activation -// no new collation should be generated. -#[rstest] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT - 1)] -#[case(RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT)] -fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( - #[case] runtime_version: u32, -) { - let activated_hash: Hash = [1; 32].into(); +#[test] +fn v2_receipts_failed_core_index_check() { + let relay_parent = Hash::repeat_byte(0); + let validation_code_hash = ValidationCodeHash::from(Hash::repeat_byte(42)); + let parent_head = dummy_head_data(); let para_id = ParaId::from(5); - - // One core, in occupied state. The data in `CoreState` and `ClaimQueue` should match. - let cores: Vec = vec![CoreState::Occupied(polkadot_primitives::OccupiedCore { - next_up_on_available: Some(ScheduledCore { para_id, collator: None }), - occupied_since: 1, - time_out_at: 10, - next_up_on_time_out: Some(ScheduledCore { para_id, collator: None }), - availability: Default::default(), // doesn't matter - group_responsible: polkadot_primitives::GroupIndex(0), - candidate_hash: Default::default(), - candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), - })]; - let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]).into(); + let expected_pvd = PersistedValidationData { + parent_head: parent_head.clone(), + relay_parent_number: 10, + relay_parent_storage_root: Hash::repeat_byte(1), + max_pov_size: 1024, + }; test_harness(|mut virtual_overseer| async move { - helpers::initialize_collator(&mut virtual_overseer, para_id).await; - helpers::activate_new_head(&mut virtual_overseer, activated_hash).await; + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::Initialize(test_config_no_collator(para_id)), + }) + .await; - helpers::handle_runtime_calls_on_new_head_activation( + virtual_overseer + .send(FromOrchestra::Communication { + msg: CollationGenerationMessage::SubmitCollation(SubmitCollationParams { + relay_parent, + collation: test_collation(), + parent_head: dummy_head_data(), + validation_code_hash, + result_sender: None, + core_index: CoreIndex(0), + }), + }) + .await; + + helpers::handle_runtime_calls_on_submit_collation( &mut virtual_overseer, - activated_hash, - AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: 0 }, - cores, - runtime_version, - claim_queue, + relay_parent, + para_id, + expected_pvd.clone(), + node_features_with_v2_enabled(), + // Core index commitment is on core 0 but don't add any assignment for core 0. + [(CoreIndex(1), [para_id].into_iter().collect())].into_iter().collect(), ) .await; + // No collation is distributed. + virtual_overseer }); } - mod helpers { - use polkadot_primitives::{ - async_backing::{Constraints, InboundHrmpLimitations}, - BlockNumber, - }; - use super::*; - - // A set for dummy constraints for `ParaBackingState`` - pub(crate) fn dummy_constraints( - min_relay_parent_number: BlockNumber, - valid_watermarks: Vec, - required_parent: HeadData, - validation_code_hash: ValidationCodeHash, - ) -> Constraints { - Constraints { - min_relay_parent_number, - max_pov_size: 5 * 1024 * 1024, - max_code_size: 1_000_000, - ump_remaining: 10, - ump_remaining_bytes: 1_000, - max_ump_num_per_candidate: 10, - dmp_remaining_messages: vec![], - hrmp_inbound: InboundHrmpLimitations { valid_watermarks }, - hrmp_channels_out: vec![], - max_hrmp_num_per_candidate: 0, - required_parent, - validation_code_hash, - upgrade_restriction: None, - future_validation_code: None, - } - } + use std::collections::{BTreeMap, VecDeque}; // Sends `Initialize` with a collator config pub async fn initialize_collator(virtual_overseer: &mut VirtualOverseer, para_id: ParaId) { @@ -1096,22 +429,18 @@ mod helpers { .await; } - // Handle all runtime calls performed in `handle_new_activations`. Conditionally expects a - // `CLAIM_QUEUE_RUNTIME_REQUIREMENT` call if the passed `runtime_version` is greater or equal to - // `CLAIM_QUEUE_RUNTIME_REQUIREMENT` + // Handle all runtime calls performed in `handle_new_activation`. pub async fn handle_runtime_calls_on_new_head_activation( virtual_overseer: &mut VirtualOverseer, activated_hash: Hash, - async_backing_params: AsyncBackingParams, - cores: Vec, - runtime_version: u32, claim_queue: BTreeMap>, + node_features: NodeFeatures, ) { assert_matches!( overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::AvailabilityCores(tx))) => { + AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::SessionIndexForChild(tx))) => { assert_eq!(hash, activated_hash); - let _ = tx.send(Ok(cores)); + tx.send(Ok(1)).unwrap(); } ); @@ -1119,73 +448,46 @@ mod helpers { overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::Validators(tx))) => { assert_eq!(hash, activated_hash); - let _ = tx.send(Ok(vec![ + tx.send(Ok(vec![ Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into(), Sr25519Keyring::Charlie.public().into(), - ])); + ])).unwrap(); } ); - let async_backing_response = - if runtime_version >= RuntimeApiRequest::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT { - Ok(async_backing_params) - } else { - Err(RuntimeApiError::NotSupported { runtime_api_name: "async_backing_params" }) - }; - assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::AsyncBackingParams( - tx, - ), - )) => { + hash, + RuntimeApiRequest::NodeFeatures(session_index, tx), + )) => { + assert_eq!(1, session_index); assert_eq!(hash, activated_hash); - let _ = tx.send(async_backing_response); + + tx.send(Ok(node_features)).unwrap(); } ); assert_matches!( overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::Version(tx), - )) => { + AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::ClaimQueue(tx))) => { assert_eq!(hash, activated_hash); - let _ = tx.send(Ok(runtime_version)); + tx.send(Ok(claim_queue)).unwrap(); } ); - - if runtime_version == RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - hash, - RuntimeApiRequest::ClaimQueue(tx), - )) => { - assert_eq!(hash, activated_hash); - let _ = tx.send(Ok(claim_queue.into())); - } - ); - } } - // Handles all runtime requests performed in `handle_new_activations` for the case when a + // Handles all runtime requests performed in `handle_new_activation` for the case when a // collation should be prepared for the new leaf pub async fn handle_cores_processing_for_a_leaf( virtual_overseer: &mut VirtualOverseer, activated_hash: Hash, para_id: ParaId, - expected_occupied_core_assumption: OccupiedCoreAssumption, - cores_assigned: usize, - pending_availability: Vec, - runtime_version: u32, + cores_assigned: Vec, ) { // Expect no messages if no cores is assigned to the para - if cores_assigned == 0 { - assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + if cores_assigned.is_empty() { return } @@ -1199,23 +501,12 @@ mod helpers { max_pov_size: 1024, }; - if runtime_version >= RuntimeApiRequest::ASYNC_BACKING_STATE_RUNTIME_REQUIREMENT { - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request(parent, RuntimeApiRequest::ParaBackingState(p_id, tx)) - ) if parent == activated_hash && p_id == para_id => { - tx.send(Ok(Some(dummy_backing_state(pending_availability)))).unwrap(); - } - ); - } - assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request(hash, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { assert_eq!(hash, activated_hash); assert_eq!(id, para_id); - assert_eq!(a, expected_occupied_core_assumption); + assert_eq!(a, OccupiedCoreAssumption::Included); let _ = tx.send(Ok(Some(pvd.clone()))); } @@ -1233,26 +524,93 @@ mod helpers { )) => { assert_eq!(hash, activated_hash); assert_eq!(id, para_id); - assert_eq!(assumption, expected_occupied_core_assumption); + assert_eq!(assumption, OccupiedCoreAssumption::Included); let _ = tx.send(Ok(Some(validation_code_hash))); } ); - for _ in 0..cores_assigned { + for core in cores_assigned { assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::CollatorProtocol(CollatorProtocolMessage::DistributeCollation{ candidate_receipt, parent_head_data_hash, + core_index, .. }) => { + assert_eq!(CoreIndex(core), core_index); assert_eq!(parent_head_data_hash, parent_head.hash()); - assert_eq!(candidate_receipt.descriptor().persisted_validation_data_hash, pvd.hash()); - assert_eq!(candidate_receipt.descriptor().para_head, dummy_head_data().hash()); - assert_eq!(candidate_receipt.descriptor().validation_code_hash, validation_code_hash); + assert_eq!(candidate_receipt.descriptor().persisted_validation_data_hash(), pvd.hash()); + assert_eq!(candidate_receipt.descriptor().para_head(), dummy_head_data().hash()); + assert_eq!(candidate_receipt.descriptor().validation_code_hash(), validation_code_hash); } ); } } + + // Handles all runtime requests performed in `handle_submit_collation` + pub async fn handle_runtime_calls_on_submit_collation( + virtual_overseer: &mut VirtualOverseer, + relay_parent: Hash, + para_id: ParaId, + expected_pvd: PersistedValidationData, + node_features: NodeFeatures, + claim_queue: BTreeMap>, + ) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::PersistedValidationData(id, a, tx))) => { + assert_eq!(rp, relay_parent); + assert_eq!(id, para_id); + assert_eq!(a, OccupiedCoreAssumption::TimedOut); + + tx.send(Ok(Some(expected_pvd))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + rp, + RuntimeApiRequest::ClaimQueue(tx), + )) => { + assert_eq!(rp, relay_parent); + tx.send(Ok(claim_queue)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::SessionIndexForChild(tx))) => { + assert_eq!(rp, relay_parent); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(rp, RuntimeApiRequest::Validators(tx))) => { + assert_eq!(rp, relay_parent); + tx.send(Ok(vec![ + Sr25519Keyring::Alice.public().into(), + Sr25519Keyring::Bob.public().into(), + Sr25519Keyring::Charlie.public().into(), + ])).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + rp, + RuntimeApiRequest::NodeFeatures(session_index, tx), + )) => { + assert_eq!(1, session_index); + assert_eq!(rp, relay_parent); + + tx.send(Ok(node_features.clone())).unwrap(); + } + ); + } } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 2c3db866566c..f9754d2babc9 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -53,6 +53,7 @@ kvdb-memorydb = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } log = { 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_checking.rs b/polkadot/node/core/approval-voting/src/approval_checking.rs index 3774edc69981..3b7262a46826 100644 --- a/polkadot/node/core/approval-voting/src/approval_checking.rs +++ b/polkadot/node/core/approval-voting/src/approval_checking.rs @@ -509,13 +509,13 @@ mod tests { use crate::{approval_db, BTreeMap}; use bitvec::{bitvec, order::Lsb0 as BitOrderLsb0, vec::BitVec}; use polkadot_primitives::GroupIndex; - use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; + use polkadot_primitives_test_helpers::{dummy_candidate_receipt_v2, dummy_hash}; #[test] fn pending_is_not_approved() { let candidate = CandidateEntry::from_v1( approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), + candidate: dummy_candidate_receipt_v2(dummy_hash()), session: 0, block_assignments: BTreeMap::default(), approvals: BitVec::default(), @@ -550,7 +550,7 @@ mod tests { fn exact_takes_only_assignments_up_to() { let mut candidate: CandidateEntry = CandidateEntry::from_v1( approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), + candidate: dummy_candidate_receipt_v2(dummy_hash()), session: 0, block_assignments: BTreeMap::default(), approvals: bitvec![u8, BitOrderLsb0; 0; 10], @@ -624,7 +624,7 @@ mod tests { fn one_honest_node_always_approves() { let mut candidate: CandidateEntry = CandidateEntry::from_v1( approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), + candidate: dummy_candidate_receipt_v2(dummy_hash()), session: 0, block_assignments: BTreeMap::default(), approvals: bitvec![u8, BitOrderLsb0; 0; 10], @@ -1097,7 +1097,7 @@ mod tests { let mut candidate: CandidateEntry = CandidateEntry::from_v1( approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), + candidate: dummy_candidate_receipt_v2(dummy_hash()), session: 0, block_assignments: BTreeMap::default(), approvals: bitvec![u8, BitOrderLsb0; 0; 3], diff --git a/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs index 53e9db64f636..87a1d20b92f5 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v1/mod.rs @@ -25,8 +25,8 @@ use codec::{Decode, Encode}; use polkadot_node_primitives::approval::v1::{AssignmentCert, DelayTranche}; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex, - ValidatorIndex, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, CoreIndex, + GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; use std::collections::BTreeMap; diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs index cd9256a5d47e..63c6cbf40b89 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs @@ -21,8 +21,8 @@ use polkadot_node_primitives::approval::{v1::DelayTranche, v2::AssignmentCertV2} use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; use polkadot_node_subsystem_util::database::{DBTransaction, Database}; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash, - SessionIndex, ValidatorIndex, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, CandidateIndex, + CoreIndex, GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs index 06a3cc1e306b..866702f861c1 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs @@ -26,7 +26,8 @@ use crate::{ ops::{add_block_entry, canonicalize, force_approve, NewCandidateInfo}, }; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, + vstaging::{CandidateReceiptV2 as CandidateReceipt, MutateDescriptorV2}, + BlockNumber, CandidateHash, CoreIndex, GroupIndex, Hash, }; use polkadot_node_subsystem_util::database::Database; @@ -35,7 +36,8 @@ use sp_consensus_slots::Slot; use std::{collections::HashMap, sync::Arc}; use polkadot_primitives_test_helpers::{ - dummy_candidate_receipt, dummy_candidate_receipt_bad_sig, dummy_hash, + dummy_candidate_receipt_bad_sig, dummy_candidate_receipt_v2, + dummy_candidate_receipt_v2_bad_sig, dummy_hash, }; const DATA_COL: u32 = 0; @@ -72,10 +74,10 @@ fn make_block_entry( } fn make_candidate(para_id: ParaId, relay_parent: Hash) -> CandidateReceipt { - let mut c = dummy_candidate_receipt(dummy_hash()); + let mut c = dummy_candidate_receipt_v2(dummy_hash()); - c.descriptor.para_id = para_id; - c.descriptor.relay_parent = relay_parent; + c.descriptor.set_para_id(para_id); + c.descriptor.set_relay_parent(relay_parent); c } @@ -95,7 +97,7 @@ fn read_write() { make_block_entry(hash_a, Default::default(), 1, vec![(CoreIndex(0), candidate_hash)]); let candidate_entry = CandidateEntry { - candidate: dummy_candidate_receipt_bad_sig(dummy_hash(), None), + candidate: dummy_candidate_receipt_v2_bad_sig(dummy_hash(), None), session: 5, block_assignments: vec![( hash_a, diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs index 7118fb6770fd..bc34f88af80a 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs @@ -25,8 +25,8 @@ use polkadot_node_subsystem::SubsystemResult; use polkadot_node_subsystem_util::database::{DBTransaction, Database}; use polkadot_overseer::SubsystemError; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash, - SessionIndex, ValidatorIndex, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, CandidateIndex, + CoreIndex, GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; 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 d2a1d7d400b1..372dd49803cb 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 @@ -25,7 +25,8 @@ use crate::{ ops::{add_block_entry, canonicalize, force_approve, NewCandidateInfo}, }; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, + vstaging::{CandidateReceiptV2 as CandidateReceipt, MutateDescriptorV2}, + BlockNumber, CandidateHash, CoreIndex, GroupIndex, Hash, }; use polkadot_node_subsystem_util::database::Database; @@ -34,7 +35,7 @@ use sp_consensus_slots::Slot; use std::{collections::HashMap, sync::Arc}; use polkadot_primitives_test_helpers::{ - dummy_candidate_receipt, dummy_candidate_receipt_bad_sig, dummy_hash, + dummy_candidate_receipt_v2, dummy_candidate_receipt_v2_bad_sig, dummy_hash, }; const DATA_COL: u32 = 0; @@ -72,12 +73,12 @@ fn make_block_entry( } fn make_candidate(para_id: ParaId, relay_parent: Hash) -> CandidateReceipt { - let mut c = dummy_candidate_receipt(dummy_hash()); + let mut c = dummy_candidate_receipt_v2(dummy_hash()); - c.descriptor.para_id = para_id; - c.descriptor.relay_parent = relay_parent; + c.descriptor.set_para_id(para_id); + c.descriptor.set_relay_parent(relay_parent); - c + c.into() } #[test] @@ -86,7 +87,7 @@ fn read_write() { let hash_a = Hash::repeat_byte(1); let hash_b = Hash::repeat_byte(2); - let candidate_hash = dummy_candidate_receipt_bad_sig(dummy_hash(), None).hash(); + let candidate_hash = dummy_candidate_receipt_v2_bad_sig(dummy_hash(), None).hash(); let range = StoredBlockRange(10, 20); let at_height = vec![hash_a, hash_b]; @@ -95,7 +96,7 @@ fn read_write() { make_block_entry(hash_a, Default::default(), 1, vec![(CoreIndex(0), candidate_hash)]); let candidate_entry = CandidateEntry { - candidate: dummy_candidate_receipt_bad_sig(dummy_hash(), None), + candidate: dummy_candidate_receipt_v2_bad_sig(dummy_hash(), None), session: 5, block_assignments: vec![( hash_a, diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index e50a2f911489..be7b3103ab13 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -45,8 +45,9 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{determine_new_blocks, runtime::RuntimeInfo}; use polkadot_overseer::SubsystemSender; use polkadot_primitives::{ - node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ConsensusLog, - CoreIndex, GroupIndex, Hash, Header, SessionIndex, + node_features, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt}, + BlockNumber, CandidateHash, ConsensusLog, CoreIndex, GroupIndex, Hash, Header, SessionIndex, }; use sc_keystore::LocalKeystore; use sp_consensus_slots::Slot; @@ -618,10 +619,10 @@ pub(crate) mod tests { use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::database::Database; use polkadot_primitives::{ - node_features::FeatureIndex, ExecutorParams, Id as ParaId, IndexedVec, NodeFeatures, - SessionInfo, ValidatorId, ValidatorIndex, + node_features::FeatureIndex, vstaging::MutateDescriptorV2, ExecutorParams, Id as ParaId, + IndexedVec, NodeFeatures, SessionInfo, ValidatorId, ValidatorIndex, }; - use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; + use polkadot_primitives_test_helpers::{dummy_candidate_receipt_v2, dummy_hash}; use schnellru::{ByLength, LruMap}; pub(crate) use sp_consensus_babe::{ digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest}, @@ -764,9 +765,9 @@ pub(crate) mod tests { let hash = header.hash(); let make_candidate = |para_id| { - let mut r = dummy_candidate_receipt(dummy_hash()); - r.descriptor.para_id = para_id; - r.descriptor.relay_parent = hash; + let mut r = dummy_candidate_receipt_v2(dummy_hash()); + r.descriptor.set_para_id(para_id); + r.descriptor.set_relay_parent(hash); r }; let candidates = vec![ @@ -917,9 +918,9 @@ pub(crate) mod tests { let hash = header.hash(); let make_candidate = |para_id| { - let mut r = dummy_candidate_receipt(dummy_hash()); - r.descriptor.para_id = para_id; - r.descriptor.relay_parent = hash; + let mut r = dummy_candidate_receipt_v2(dummy_hash()); + r.descriptor.set_para_id(para_id); + r.descriptor.set_relay_parent(hash); r }; let candidates = vec![ @@ -1056,9 +1057,9 @@ pub(crate) mod tests { let hash = header.hash(); let make_candidate = |para_id| { - let mut r = dummy_candidate_receipt(dummy_hash()); - r.descriptor.para_id = para_id; - r.descriptor.relay_parent = hash; + let mut r = dummy_candidate_receipt_v2(dummy_hash()); + r.descriptor.set_para_id(para_id); + r.descriptor.set_relay_parent(hash); r }; let candidates = vec![ @@ -1150,9 +1151,9 @@ pub(crate) mod tests { let hash = header.hash(); let make_candidate = |para_id| { - let mut r = dummy_candidate_receipt(dummy_hash()); - r.descriptor.para_id = para_id; - r.descriptor.relay_parent = hash; + let mut r = dummy_candidate_receipt_v2(dummy_hash()); + r.descriptor.set_para_id(para_id); + r.descriptor.set_relay_parent(hash); r }; let candidates = vec![ @@ -1340,9 +1341,9 @@ pub(crate) mod tests { let hash = header.hash(); let make_candidate = |para_id| { - let mut r = dummy_candidate_receipt(dummy_hash()); - r.descriptor.para_id = para_id; - r.descriptor.relay_parent = hash; + let mut r = dummy_candidate_receipt_v2(dummy_hash()); + r.descriptor.set_para_id(para_id); + r.descriptor.set_relay_parent(hash); r }; let candidates = vec![ diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 835098293050..2176cc7675be 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -38,7 +38,7 @@ use polkadot_node_subsystem::{ ApprovalVotingMessage, AssignmentCheckError, AssignmentCheckResult, AvailabilityRecoveryMessage, BlockDescription, CandidateValidationMessage, ChainApiMessage, ChainSelectionMessage, CheckedIndirectAssignment, CheckedIndirectSignedApprovalVote, - DisputeCoordinatorMessage, HighestApprovedAncestorBlock, RuntimeApiMessage, + DisputeCoordinatorMessage, HighestApprovedAncestorBlock, PvfExecKind, RuntimeApiMessage, RuntimeApiRequest, }, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, @@ -52,9 +52,10 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - ApprovalVoteMultipleCandidates, ApprovalVotingParams, BlockNumber, CandidateHash, - CandidateIndex, CandidateReceipt, CoreIndex, ExecutorParams, GroupIndex, Hash, PvfExecKind, - SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, ApprovalVoteMultipleCandidates, + ApprovalVotingParams, BlockNumber, CandidateHash, CandidateIndex, CoreIndex, ExecutorParams, + GroupIndex, Hash, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorPair, + ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; @@ -2824,7 +2825,7 @@ where target: LOG_TARGET, validator_index = approval.validator.0, candidate_hash = ?approved_candidate_hash, - para_id = ?candidate_entry.candidate_receipt().descriptor.para_id, + para_id = ?candidate_entry.candidate_receipt().descriptor.para_id(), "Importing approval vote", ); @@ -2923,7 +2924,7 @@ where let block_hash = block_entry.block_hash(); let block_number = block_entry.block_number(); let session_index = block_entry.session(); - let para_id = candidate_entry.candidate_receipt().descriptor().para_id; + let para_id = candidate_entry.candidate_receipt().descriptor().para_id(); let tick_now = state.clock.tick_now(); let (is_approved, status) = if let Some((approval_entry, status)) = state @@ -3221,7 +3222,7 @@ async fn process_wakeup>( gum::trace!( target: LOG_TARGET, ?candidate_hash, - para_id = ?candidate_receipt.descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id(), block_hash = ?relay_block, "Launching approval work.", ); @@ -3352,7 +3353,7 @@ async fn launch_approval< } let candidate_hash = candidate.hash(); - let para_id = candidate.descriptor.para_id; + let para_id = candidate.descriptor.para_id(); gum::trace!(target: LOG_TARGET, ?candidate_hash, ?para_id, "Recovering data."); let timer = metrics.time_recover_and_approve(); @@ -3370,7 +3371,7 @@ async fn launch_approval< .send_message(RuntimeApiMessage::Request( block_hash, RuntimeApiRequest::ValidationCodeByHash( - candidate.descriptor.validation_code_hash, + candidate.descriptor.validation_code_hash(), code_tx, ), )) @@ -3393,7 +3394,7 @@ async fn launch_approval< ?para_id, ?candidate_hash, "Data unavailable for candidate {:?}", - (candidate_hash, candidate.descriptor.para_id), + (candidate_hash, candidate.descriptor.para_id()), ); // do nothing. we'll just be a no-show and that'll cause others to rise up. metrics_guard.take().on_approval_unavailable(); @@ -3404,7 +3405,7 @@ async fn launch_approval< ?para_id, ?candidate_hash, "Channel closed while recovering data for candidate {:?}", - (candidate_hash, candidate.descriptor.para_id), + (candidate_hash, candidate.descriptor.para_id()), ); // do nothing. we'll just be a no-show and that'll cause others to rise up. metrics_guard.take().on_approval_unavailable(); @@ -3415,7 +3416,7 @@ async fn launch_approval< ?para_id, ?candidate_hash, "Data recovery invalid for candidate {:?}", - (candidate_hash, candidate.descriptor.para_id), + (candidate_hash, candidate.descriptor.para_id()), ); issue_local_invalid_statement( &mut sender, @@ -3438,7 +3439,7 @@ async fn launch_approval< gum::warn!( target: LOG_TARGET, "Validation code unavailable for block {:?} in the state of block {:?} (a recent descendant)", - candidate.descriptor.relay_parent, + candidate.descriptor.relay_parent(), block_hash, ); diff --git a/polkadot/node/core/approval-voting/src/ops.rs b/polkadot/node/core/approval-voting/src/ops.rs index 2a8fdba5aa36..f105580009fa 100644 --- a/polkadot/node/core/approval-voting/src/ops.rs +++ b/polkadot/node/core/approval-voting/src/ops.rs @@ -20,7 +20,9 @@ use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; use bitvec::order::Lsb0 as BitOrderLsb0; -use polkadot_primitives::{BlockNumber, CandidateHash, CandidateReceipt, GroupIndex, Hash}; +use polkadot_primitives::{ + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, GroupIndex, Hash, +}; use std::collections::{hash_map::Entry, BTreeMap, HashMap}; diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs index 16e231aa1a2d..d891af01c3ab 100644 --- a/polkadot/node/core/approval-voting/src/persisted_entries.rs +++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs @@ -26,8 +26,8 @@ use polkadot_node_primitives::approval::{ v2::{AssignmentCertV2, CandidateBitfield}, }; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash, - SessionIndex, ValidatorIndex, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, CandidateIndex, + CoreIndex, GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index db5ffd441c0d..099ab419dfbf 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -42,8 +42,9 @@ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_overseer::SpawnGlue; use polkadot_primitives::{ - ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, DisputeStatement, GroupIndex, - Header, Id as ParaId, IndexedVec, NodeFeatures, ValidDisputeStatementKind, ValidationCode, + vstaging::{CandidateEvent, MutateDescriptorV2}, + ApprovalVote, CandidateCommitments, CoreIndex, DisputeStatement, GroupIndex, Header, + Id as ParaId, IndexedVec, NodeFeatures, ValidDisputeStatementKind, ValidationCode, ValidatorSignature, }; use std::{cmp::max, time::Duration}; @@ -69,7 +70,9 @@ use super::{ }, }; -use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_candidate_receipt_bad_sig}; +use polkadot_primitives_test_helpers::{ + dummy_candidate_receipt_v2, dummy_candidate_receipt_v2_bad_sig, +}; const SLOT_DURATION_MILLIS: u64 = 5000; @@ -638,8 +641,8 @@ where } fn make_candidate(para_id: ParaId, hash: &Hash) -> CandidateReceipt { - let mut r = dummy_candidate_receipt_bad_sig(*hash, Some(Default::default())); - r.descriptor.para_id = para_id; + let mut r = dummy_candidate_receipt_v2_bad_sig(*hash, Some(Default::default())); + r.descriptor.set_para_id(para_id); r } @@ -1282,7 +1285,7 @@ fn subsystem_rejects_approval_if_no_block_entry() { let block_hash = Hash::repeat_byte(0x01); let candidate_index = 0; let validator = ValidatorIndex(0); - let candidate_hash = dummy_candidate_receipt(block_hash).hash(); + let candidate_hash = dummy_candidate_receipt_v2(block_hash).hash(); let session_index = 1; let rx = import_approval( @@ -1324,9 +1327,9 @@ fn subsystem_rejects_approval_before_assignment() { let candidate_hash = { let mut candidate_receipt = - dummy_candidate_receipt_bad_sig(block_hash, Some(Default::default())); - candidate_receipt.descriptor.para_id = ParaId::from(0_u32); - candidate_receipt.descriptor.relay_parent = block_hash; + dummy_candidate_receipt_v2_bad_sig(block_hash, Some(Default::default())); + candidate_receipt.descriptor.set_para_id(ParaId::from(0_u32)); + candidate_receipt.descriptor.set_relay_parent(block_hash); candidate_receipt.hash() }; @@ -1390,15 +1393,17 @@ fn subsystem_accepts_duplicate_assignment() { let block_hash = Hash::repeat_byte(0x01); let candidate_receipt1 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(1_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(1_u32)); receipt - }; + } + .into(); let candidate_receipt2 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(2_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(2_u32)); receipt - }; + } + .into(); let candidate_index1 = 0; let candidate_index2 = 1; @@ -1572,9 +1577,9 @@ fn subsystem_accepts_and_imports_approval_after_assignment() { let candidate_hash = { let mut candidate_receipt = - dummy_candidate_receipt_bad_sig(block_hash, Some(Default::default())); - candidate_receipt.descriptor.para_id = ParaId::from(0_u32); - candidate_receipt.descriptor.relay_parent = block_hash; + dummy_candidate_receipt_v2_bad_sig(block_hash, Some(Default::default())); + candidate_receipt.descriptor.set_para_id(ParaId::from(0_u32)); + candidate_receipt.descriptor.set_relay_parent(block_hash); candidate_receipt.hash() }; @@ -1643,9 +1648,9 @@ fn subsystem_second_approval_import_only_schedules_wakeups() { let candidate_hash = { let mut candidate_receipt = - dummy_candidate_receipt_bad_sig(block_hash, Some(Default::default())); - candidate_receipt.descriptor.para_id = ParaId::from(0_u32); - candidate_receipt.descriptor.relay_parent = block_hash; + dummy_candidate_receipt_v2_bad_sig(block_hash, Some(Default::default())); + candidate_receipt.descriptor.set_para_id(ParaId::from(0_u32)); + candidate_receipt.descriptor.set_relay_parent(block_hash); candidate_receipt.hash() }; @@ -2402,13 +2407,13 @@ fn subsystem_import_checked_approval_sets_one_block_bit_at_a_time() { let block_hash = Hash::repeat_byte(0x01); let candidate_receipt1 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(1_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(1_u32)); receipt }; let candidate_receipt2 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(2_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(2_u32)); receipt }; let candidate_hash1 = candidate_receipt1.hash(); @@ -2566,18 +2571,18 @@ fn inclusion_events_can_be_unordered_by_core_index() { let block_hash = Hash::repeat_byte(0x01); let candidate_receipt0 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(0_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(0_u32)); receipt }; let candidate_receipt1 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(1_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(1_u32)); receipt }; let candidate_receipt2 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(2_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(2_u32)); receipt }; let candidate_index0 = 0; @@ -2710,8 +2715,8 @@ fn approved_ancestor_test( .iter() .enumerate() .map(|(i, hash)| { - let mut candidate_receipt = dummy_candidate_receipt(*hash); - candidate_receipt.descriptor.para_id = i.into(); + let mut candidate_receipt = dummy_candidate_receipt_v2(*hash); + candidate_receipt.descriptor.set_para_id(i.into()); candidate_receipt }) .collect(); @@ -2882,7 +2887,7 @@ fn subsystem_validate_approvals_cache() { let block_hash = Hash::repeat_byte(0x01); let fork_block_hash = Hash::repeat_byte(0x02); let candidate_commitments = CandidateCommitments::default(); - let mut candidate_receipt = dummy_candidate_receipt(block_hash); + let mut candidate_receipt = dummy_candidate_receipt_v2(block_hash); candidate_receipt.commitments_hash = candidate_commitments.hash(); let candidate_hash = candidate_receipt.hash(); let slot = Slot::from(1); @@ -3012,13 +3017,13 @@ fn subsystem_doesnt_distribute_duplicate_compact_assignments() { let block_hash = Hash::repeat_byte(0x01); let candidate_receipt1 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(1_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(1_u32)); receipt }; let candidate_receipt2 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(2_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(2_u32)); receipt }; let candidate_index1 = 0; @@ -3263,7 +3268,7 @@ where ); let block_hash = Hash::repeat_byte(0x01); - let candidate_receipt = dummy_candidate_receipt(block_hash); + let candidate_receipt = dummy_candidate_receipt_v2(block_hash); let candidate_hash = candidate_receipt.hash(); let slot = Slot::from(1); let candidate_index = 0; @@ -3965,8 +3970,8 @@ fn test_approval_is_sent_on_max_approval_coalesce_count() { let candidate_commitments = CandidateCommitments::default(); let candidate_receipt1 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(1_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(1_u32)); receipt.commitments_hash = candidate_commitments.hash(); receipt }; @@ -3974,8 +3979,8 @@ fn test_approval_is_sent_on_max_approval_coalesce_count() { let candidate_hash1 = candidate_receipt1.hash(); let candidate_receipt2 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(2_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(2_u32)); receipt.commitments_hash = candidate_commitments.hash(); receipt }; @@ -4266,8 +4271,8 @@ fn test_approval_is_sent_on_max_approval_coalesce_wait() { let candidate_commitments = CandidateCommitments::default(); let candidate_receipt1 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(1_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(1_u32)); receipt.commitments_hash = candidate_commitments.hash(); receipt }; @@ -4275,8 +4280,8 @@ fn test_approval_is_sent_on_max_approval_coalesce_wait() { let candidate_hash1 = candidate_receipt1.hash(); let candidate_receipt2 = { - let mut receipt = dummy_candidate_receipt(block_hash); - receipt.descriptor.para_id = ParaId::from(2_u32); + let mut receipt = dummy_candidate_receipt_v2(block_hash); + receipt.descriptor.set_para_id(ParaId::from(2_u32)); receipt.commitments_hash = candidate_commitments.hash(); receipt }; @@ -4420,7 +4425,7 @@ async fn setup_overseer_with_two_blocks_each_with_one_assignment_triggered( let block_hash = Hash::repeat_byte(0x01); let fork_block_hash = Hash::repeat_byte(0x02); let candidate_commitments = CandidateCommitments::default(); - let mut candidate_receipt = dummy_candidate_receipt(block_hash); + let mut candidate_receipt = dummy_candidate_receipt_v2(block_hash); candidate_receipt.commitments_hash = candidate_commitments.hash(); let candidate_hash = candidate_receipt.hash(); let slot = Slot::from(1); @@ -4549,7 +4554,7 @@ fn subsystem_relaunches_approval_work_on_restart() { let block_hash = Hash::repeat_byte(0x01); let fork_block_hash = Hash::repeat_byte(0x02); let candidate_commitments = CandidateCommitments::default(); - let mut candidate_receipt = dummy_candidate_receipt(block_hash); + let mut candidate_receipt = dummy_candidate_receipt_v2(block_hash); candidate_receipt.commitments_hash = candidate_commitments.hash(); let slot = Slot::from(1); clock.inner.lock().set_tick(slot_to_tick(slot + 2)); @@ -4805,7 +4810,7 @@ fn subsystem_sends_pending_approvals_on_approval_restart() { let block_hash = Hash::repeat_byte(0x01); let fork_block_hash = Hash::repeat_byte(0x02); let candidate_commitments = CandidateCommitments::default(); - let mut candidate_receipt = dummy_candidate_receipt(block_hash); + let mut candidate_receipt = dummy_candidate_receipt_v2(block_hash); candidate_receipt.commitments_hash = candidate_commitments.hash(); let slot = Slot::from(1); @@ -4815,7 +4820,7 @@ fn subsystem_sends_pending_approvals_on_approval_restart() { fork_block_hash, slot, sync_oracle_handle, - candidate_receipt, + candidate_receipt.into(), ) .await; chain_builder.build(&mut virtual_overseer).await; diff --git a/polkadot/node/core/av-store/src/lib.rs b/polkadot/node/core/av-store/src/lib.rs index 9473040e8f5e..9da2973773a0 100644 --- a/polkadot/node/core/av-store/src/lib.rs +++ b/polkadot/node/core/av-store/src/lib.rs @@ -47,8 +47,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util as util; use polkadot_primitives::{ - BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ChunkIndex, CoreIndex, Hash, - Header, NodeFeatures, ValidatorIndex, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt}, + BlockNumber, CandidateHash, ChunkIndex, CoreIndex, Hash, Header, NodeFeatures, ValidatorIndex, }; use util::availability_chunks::availability_chunk_indices; diff --git a/polkadot/node/core/av-store/src/tests.rs b/polkadot/node/core/av-store/src/tests.rs index 958917a3104f..80043e56976b 100644 --- a/polkadot/node/core/av-store/src/tests.rs +++ b/polkadot/node/core/av-store/src/tests.rs @@ -31,8 +31,8 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{database::Database, TimeoutExt}; use polkadot_primitives::{ - node_features, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, HeadData, Header, - PersistedValidationData, ValidatorId, + node_features, vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, CoreIndex, + GroupIndex, HeadData, Header, PersistedValidationData, ValidatorId, }; use polkadot_primitives_test_helpers::TestCandidateBuilder; use sp_keyring::Sr25519Keyring; diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index 1b52afc309bc..cd1acf9daa93 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -14,6 +14,7 @@ futures = { workspace = true } sp-keystore = { workspace = true, default-features = true } polkadot-primitives = { 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 } @@ -35,3 +36,4 @@ assert_matches = { workspace = true } rstest = { workspace = true } polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } +polkadot-primitives = { workspace = true, features = ["test"] } diff --git a/polkadot/node/core/backing/src/error.rs b/polkadot/node/core/backing/src/error.rs index 568f71402644..e1852be826f4 100644 --- a/polkadot/node/core/backing/src/error.rs +++ b/polkadot/node/core/backing/src/error.rs @@ -24,7 +24,7 @@ use polkadot_node_subsystem::{ RuntimeApiError, SubsystemError, }; use polkadot_node_subsystem_util::{runtime, Error as UtilError}; -use polkadot_primitives::{BackedCandidate, ValidationCodeHash}; +use polkadot_primitives::{vstaging::BackedCandidate, ValidationCodeHash}; use crate::{ParaId, LOG_TARGET}; @@ -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 f276321c87ed..8b54a8b5907b 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -89,28 +89,32 @@ use polkadot_node_subsystem::{ AvailabilityDistributionMessage, AvailabilityStoreMessage, CanSecondRequest, CandidateBackingMessage, CandidateValidationMessage, CollatorProtocolMessage, HypotheticalCandidate, HypotheticalMembershipRequest, IntroduceSecondedCandidateRequest, - ProspectiveParachainsMessage, ProvisionableData, ProvisionerMessage, RuntimeApiMessage, - RuntimeApiRequest, StatementDistributionMessage, StoreAvailableDataError, + ProspectiveParachainsMessage, ProvisionableData, ProvisionerMessage, PvfExecKind, + 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; use polkadot_primitives::{ - node_features::FeatureIndex, BackedCandidate, CandidateCommitments, CandidateHash, - CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, PersistedValidationData, - PvfExecKind, SessionIndex, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, - ValidatorSignature, ValidityAttestation, + node_features::FeatureIndex, + vstaging::{ + BackedCandidate, CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, + }, + CandidateCommitments, CandidateHash, CoreIndex, ExecutorParams, GroupIndex, GroupRotationInfo, + Hash, Id as ParaId, IndexedVec, NodeFeatures, PersistedValidationData, SessionIndex, + SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorSignature, + ValidityAttestation, }; use polkadot_statement_table::{ generic::AttestedCandidate as TableAttestedCandidate, @@ -118,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; @@ -208,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. @@ -249,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) } -} -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 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) + } + + /// 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)>, @@ -333,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, } @@ -625,6 +746,8 @@ async fn request_candidate_validation( executor_params: ExecutorParams, ) -> 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 { @@ -633,7 +756,11 @@ async fn request_candidate_validation( candidate_receipt, pov, executor_params, - exec_kind: PvfExecKind::Backing, + exec_kind: if is_system { + PvfExecKind::BackingSystemParas(relay_parent) + } else { + PvfExecKind::Backing(relay_parent) + }, response_sender: tx, }) .await; @@ -658,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, @@ -677,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, @@ -685,7 +814,7 @@ async fn validate_and_make_available( } = params; let validation_code = { - let validation_code_hash = candidate.descriptor().validation_code_hash; + let validation_code_hash = candidate.descriptor().validation_code_hash(); let (tx, rx) = oneshot::channel(); sender .send_message(RuntimeApiMessage::Request( @@ -702,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 } => @@ -718,7 +838,7 @@ async fn validate_and_make_available( &mut sender, relay_parent, from_validator, - candidate.descriptor.para_id, + candidate.descriptor.para_id(), candidate_hash, pov_hash, ) @@ -746,7 +866,7 @@ async fn validate_and_make_available( validation_code, candidate.clone(), pov.clone(), - executor_params, + executor_params.as_ref().clone(), ) .await? }; @@ -765,7 +885,7 @@ async fn validate_and_make_available( pov.clone(), candidate.hash(), validation_data.clone(), - candidate.descriptor.erasure_root, + candidate.descriptor.erasure_root(), core_index, node_features, ) @@ -842,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 => { @@ -935,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, @@ -955,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?; @@ -1047,7 +1109,7 @@ fn core_index_from_statement( } if let StatementWithPVD::Seconded(candidate, _pvd) = statement.payload() { - let candidate_para_id = candidate.descriptor.para_id; + let candidate_para_id = candidate.descriptor.para_id(); let mut assigned_paras = claim_queue.iter_claims_for_core(&core_index); if !assigned_paras.any(|id| id == &candidate_para_id) { @@ -1073,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( @@ -1140,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 } @@ -1180,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()]; - - 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 validator_to_group = + per_session_cache.validator_to_group(session_index, &validators, &validator_groups); - 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, })) } @@ -1233,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 { @@ -1244,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() { @@ -1335,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, @@ -1347,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, @@ -1406,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 = @@ -1438,14 +1436,14 @@ async fn handle_validated_candidate_command( let candidate_hash = candidate.hash(); gum::debug!( target: LOG_TARGET, - relay_parent = ?candidate.descriptor().relay_parent, + relay_parent = ?candidate.descriptor().relay_parent(), ?candidate_hash, "Attempted to second candidate but was rejected by prospective parachains", ); // Ensure the collator is reported. ctx.send_message(CollatorProtocolMessage::Invalid( - candidate.descriptor().relay_parent, + candidate.descriptor().relay_parent(), candidate, )) .await; @@ -1465,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(); @@ -1586,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, @@ -1613,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. // @@ -1625,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. @@ -1658,7 +1633,7 @@ async fn import_statement( persisted_validation_data: pvd.clone(), // This is set after importing when seconding locally. seconded_locally: false, - relay_parent: candidate.descriptor().relay_parent, + relay_parent: candidate.descriptor.relay_parent(), }, ); } @@ -1702,7 +1677,7 @@ async fn post_import_statement_actions( &rp_state.table_context, rp_state.inject_core_index, ) { - let para_id = backed.candidate().descriptor.para_id; + let para_id = backed.candidate().descriptor.para_id(); gum::debug!( target: LOG_TARGET, candidate_hash = ?candidate_hash, @@ -1711,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"); } @@ -1883,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(), @@ -1960,7 +1923,7 @@ async fn maybe_validate_and_import( .get_candidate(&candidate_hash) .ok_or(Error::CandidateNotFound)? .to_plain(), - pov_hash: receipt.descriptor.pov_hash, + pov_hash: receipt.descriptor.pov_hash(), from_validator: statement.validator_index(), backing: Vec::new(), }; @@ -2037,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(), @@ -2061,9 +2025,9 @@ async fn handle_second_message( let _timer = metrics.time_process_second(); let candidate_hash = candidate.hash(); - let relay_parent = candidate.descriptor().relay_parent; + let relay_parent = candidate.descriptor().relay_parent(); - if candidate.descriptor().persisted_validation_data_hash != persisted_validation_data.hash() { + if candidate.descriptor().persisted_validation_data_hash() != persisted_validation_data.hash() { gum::warn!( target: LOG_TARGET, ?candidate_hash, @@ -2097,12 +2061,12 @@ async fn handle_second_message( let assigned_paras = rp_state.assigned_core.and_then(|core| rp_state.claim_queue.0.get(&core)); // Sanity check that candidate is from our assignment. - if !matches!(assigned_paras, Some(paras) if paras.contains(&candidate.descriptor().para_id)) { + if !matches!(assigned_paras, Some(paras) if paras.contains(&candidate.descriptor().para_id())) { gum::debug!( target: LOG_TARGET, our_assignment_core = ?rp_state.assigned_core, our_assignment_paras = ?assigned_paras, - collation = ?candidate.descriptor().para_id, + collation = ?candidate.descriptor().para_id(), "Subsystem asked to second for para outside of our assignment", ); return Ok(()); @@ -2112,7 +2076,7 @@ async fn handle_second_message( target: LOG_TARGET, our_assignment_core = ?rp_state.assigned_core, our_assignment_paras = ?assigned_paras, - collation = ?candidate.descriptor().para_id, + collation = ?candidate.descriptor().para_id(), "Current assignments vs collation", ); diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 10eb45b82d12..1a5fbeda100c 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -14,27 +14,27 @@ // 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, 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, CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, - PvfExecKind, 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, - dummy_committed_candidate_receipt, dummy_hash, validator_pubkeys, + dummy_committed_candidate_receipt_v2, dummy_hash, validator_pubkeys, }; use polkadot_statement_table::v2::Misbehavior; use rstest::rstest; @@ -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) = @@ -236,7 +248,8 @@ impl TestCandidateBuilder { para_head: self.head_data.hash(), validation_code_hash: ValidationCode(self.validation_code).hash(), persisted_validation_data_hash: self.persisted_validation_data_hash, - }, + } + .into(), commitments: CandidateCommitments { head_data: self.head_data, upward_messages: Default::default(), @@ -249,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( @@ -433,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::Backing && - 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 { @@ -446,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(), @@ -488,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), @@ -553,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(); @@ -561,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(), @@ -575,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, @@ -617,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::Backing && - 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()); @@ -771,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]) }; @@ -880,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. @@ -1121,7 +1337,7 @@ fn extract_core_index_from_statement_works() { .flatten() .expect("should be signed"); - candidate.descriptor.para_id = test_state.chain_ids[1]; + candidate.descriptor.set_para_id(test_state.chain_ids[1]); let signed_statement_3 = SignedFullStatementWithPVD::sign( &test_state.keystore, @@ -1170,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(); @@ -1252,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 @@ -1286,8 +1517,8 @@ 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::Backing && + *pov == pov_abc && candidate_receipt.descriptor == candidate_a.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { // we never validate the candidate. our local node @@ -1304,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 = @@ -1361,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]) }; @@ -1389,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, @@ -1424,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::Backing && - 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 = @@ -1547,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(); @@ -1604,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, @@ -1620,8 +1800,8 @@ 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::Backing && + *pov == pov_block_a && candidate_receipt.descriptor == candidate_a.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate_a.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1644,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::Backing && - 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, @@ -1686,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(); } ); @@ -1707,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(); @@ -1756,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!( @@ -1787,8 +1989,8 @@ 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::Backing && + *pov == pov_a && candidate_receipt.descriptor == candidate.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1839,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, @@ -1853,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(); @@ -1900,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!( @@ -1931,8 +2148,8 @@ 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::Backing && + *pov == pov_a && candidate_receipt.descriptor == candidate.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); @@ -1999,7 +2216,7 @@ fn candidate_backing_reorders_votes() { }; let attested = TableAttestedCandidate { - candidate: dummy_committed_candidate_receipt(dummy_hash()), + candidate: dummy_committed_candidate_receipt_v2(dummy_hash()), validity_votes: vec![ (ValidatorIndex(5), fake_attestation(5)), (ValidatorIndex(3), fake_attestation(3)), @@ -2035,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], @@ -2053,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(); @@ -2111,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. @@ -2133,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); }, @@ -2180,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( @@ -2210,8 +2428,8 @@ fn retry_works() { }, ) if validation_data == pvd_a && validation_code == validation_code_a && - *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + *pov == pov_a && candidate_receipt.descriptor == candidate.descriptor && + matches!(exec_kind, PvfExecKind::BackingSystemParas(_)) && candidate.commitments.hash() == candidate_receipt.commitments_hash ); virtual_overseer @@ -2220,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(); @@ -2304,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()); @@ -2311,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 = @@ -2335,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(); @@ -2536,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(); @@ -2584,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(); @@ -2626,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); @@ -2646,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(); @@ -2665,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, @@ -2717,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::Backing && - 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 15bc0b4a1139..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::{AsyncBackingParams, BlockNumber, Header, OccupiedCore}; - -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::Backing && - 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_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/src/lib.rs b/polkadot/node/core/bitfield-signing/src/lib.rs index 474de1c66abd..7c67853503f6 100644 --- a/polkadot/node/core/bitfield-signing/src/lib.rs +++ b/polkadot/node/core/bitfield-signing/src/lib.rs @@ -34,7 +34,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ self as util, request_availability_cores, runtime::recv_runtime, Validator, }; -use polkadot_primitives::{AvailabilityBitfield, CoreState, Hash, ValidatorIndex}; +use polkadot_primitives::{vstaging::CoreState, AvailabilityBitfield, Hash, ValidatorIndex}; use sp_keystore::{Error as KeystoreError, KeystorePtr}; use std::{collections::HashMap, time::Duration}; use wasm_timer::{Delay, Instant}; diff --git a/polkadot/node/core/bitfield-signing/src/tests.rs b/polkadot/node/core/bitfield-signing/src/tests.rs index c08018375cf3..9123414844a6 100644 --- a/polkadot/node/core/bitfield-signing/src/tests.rs +++ b/polkadot/node/core/bitfield-signing/src/tests.rs @@ -17,8 +17,8 @@ use super::*; use futures::{executor::block_on, pin_mut, StreamExt}; use polkadot_node_subsystem::messages::{AllMessages, RuntimeApiMessage, RuntimeApiRequest}; -use polkadot_primitives::{CandidateHash, OccupiedCore}; -use polkadot_primitives_test_helpers::dummy_candidate_descriptor; +use polkadot_primitives::{vstaging::OccupiedCore, CandidateHash}; +use polkadot_primitives_test_helpers::dummy_candidate_descriptor_v2; fn occupied_core(para_id: u32, candidate_hash: CandidateHash) -> CoreState { CoreState::Occupied(OccupiedCore { @@ -29,7 +29,7 @@ fn occupied_core(para_id: u32, candidate_hash: CandidateHash) -> CoreState { next_up_on_time_out: None, availability: Default::default(), candidate_hash, - candidate_descriptor: dummy_candidate_descriptor(Hash::zero()), + candidate_descriptor: dummy_candidate_descriptor_v2(Hash::zero()), }) } diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index fcacc38cae65..87855dbce415 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -38,3 +38,5 @@ 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-test-helpers = { workspace = true } +rstest = { workspace = true } +polkadot-primitives = { workspace = true, features = ["test"] } diff --git a/polkadot/node/core/candidate-validation/src/lib.rs b/polkadot/node/core/candidate-validation/src/lib.rs index 50505d733916..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, RuntimeApiMessage, RuntimeApiRequest, - ValidationFailed, + CandidateValidationMessage, ChainApiMessage, PreCheckOutcome, PvfExecKind, + RuntimeApiMessage, RuntimeApiRequest, ValidationFailed, }, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, SubsystemSender, }; -use polkadot_node_subsystem_util as util; +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::{ @@ -45,9 +48,14 @@ use polkadot_primitives::{ DEFAULT_APPROVAL_EXECUTION_TIMEOUT, DEFAULT_BACKING_EXECUTION_TIMEOUT, DEFAULT_LENIENT_PREPARATION_TIMEOUT, DEFAULT_PRECHECK_PREPARATION_TIMEOUT, }, - AuthorityDiscoveryId, CandidateCommitments, CandidateDescriptor, CandidateEvent, - CandidateReceipt, ExecutorParams, Hash, PersistedValidationData, PvfExecKind, PvfPrepKind, - SessionIndex, ValidationCode, ValidationCodeHash, ValidatorId, + vstaging::{ + transpose_claim_queue, CandidateDescriptorV2 as CandidateDescriptor, CandidateEvent, + CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, + }, + AuthorityDiscoveryId, CandidateCommitments, ExecutorParams, Hash, PersistedValidationData, + PvfExecKind as RuntimePvfExecKind, PvfPrepKind, SessionIndex, ValidationCode, + ValidationCodeHash, ValidatorId, }; use sp_application_crypto::{AppCrypto, ByteArray}; use sp_keystore::KeystorePtr; @@ -144,6 +152,25 @@ impl CandidateValidationSubsystem { } } +// Returns the claim queue at relay parent and logs a warning if it is not available. +async fn claim_queue(relay_parent: Hash, sender: &mut Sender) -> Option +where + Sender: SubsystemSender, +{ + match util::runtime::fetch_claim_queue(sender, relay_parent).await { + Ok(maybe_cq) => maybe_cq, + Err(err) => { + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + ?err, + "Claim queue not available" + ); + None + }, + } +} + fn handle_validation_message( mut sender: S, validation_host: ValidationHost, @@ -163,24 +190,40 @@ where exec_kind, response_sender, .. - } => async move { - let _timer = metrics.time_validate_from_exhaustive(); - let res = validate_candidate_exhaustive( - validation_host, - validation_data, - validation_code, - candidate_receipt, - pov, - executor_params, - exec_kind, - &metrics, - ) - .await; + } => + async move { + let _timer = metrics.time_validate_from_exhaustive(); + let relay_parent = candidate_receipt.descriptor.relay_parent(); + + let maybe_claim_queue = claim_queue(relay_parent, &mut sender).await; + + let maybe_expected_session_index = + match util::request_session_index_for_child(relay_parent, &mut sender) + .await + .await + { + Ok(Ok(expected_session_index)) => Some(expected_session_index), + _ => None, + }; + + let res = validate_candidate_exhaustive( + maybe_expected_session_index, + validation_host, + validation_data, + validation_code, + candidate_receipt, + pov, + executor_params, + exec_kind, + &metrics, + maybe_claim_queue, + ) + .await; - metrics.on_validation_event(&res); - let _ = response_sender.send(res); - } - .boxed(), + metrics.on_validation_event(&res); + let _ = response_sender.send(res); + } + .boxed(), CandidateValidationMessage::PreCheck { relay_parent, validation_code_hash, @@ -239,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(..))) => {}, @@ -436,7 +480,7 @@ where .into_iter() .filter_map(|e| match e { CandidateEvent::CandidateBacked(receipt, ..) => { - let h = receipt.descriptor.validation_code_hash; + let h = receipt.descriptor.validation_code_hash(); if already_prepared.contains(&h) { None } else { @@ -511,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( @@ -633,6 +737,7 @@ where } async fn validate_candidate_exhaustive( + maybe_expected_session_index: Option, mut validation_backend: impl ValidationBackend + Send, persisted_validation_data: PersistedValidationData, validation_code: ValidationCode, @@ -641,11 +746,13 @@ async fn validate_candidate_exhaustive( executor_params: ExecutorParams, exec_kind: PvfExecKind, metrics: &Metrics, + maybe_claim_queue: Option, ) -> Result { let _timer = metrics.time_validate_candidate_exhaustive(); - let validation_code_hash = validation_code.hash(); - let para_id = candidate_receipt.descriptor.para_id; + let relay_parent = candidate_receipt.descriptor.relay_parent(); + let para_id = candidate_receipt.descriptor.para_id(); + gum::debug!( target: LOG_TARGET, ?validation_code_hash, @@ -653,6 +760,27 @@ async fn validate_candidate_exhaustive( "About to validate a candidate.", ); + // We only check the session index for backing. + match (exec_kind, candidate_receipt.descriptor.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!( + target: LOG_TARGET, + ?relay_parent, + error, + ); + + return Err(ValidationFailed(error.into())) + }; + + if session_index != expected_session_index { + return Ok(ValidationResult::Invalid(InvalidCandidate::InvalidSessionIndex)) + } + }, + (_, _) => {}, + }; + if let Err(e) = perform_basic_checks( &candidate_receipt.descriptor, persisted_validation_data.max_pov_size, @@ -667,9 +795,9 @@ 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::Backing(_) | PvfExecKind::BackingSystemParas(_) => { let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); - let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind); + let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind.into()); let pvf = PvfPrepData::from_code( validation_code.0, executor_params, @@ -683,20 +811,22 @@ async fn validate_candidate_exhaustive( exec_timeout, persisted_validation_data.clone(), pov, - polkadot_node_core_pvf::Priority::Normal, + exec_kind.into(), + exec_kind, ) .await }, - PvfExecKind::Approval => + PvfExecKind::Approval | PvfExecKind::Dispute => validation_backend .validate_candidate_with_retry( validation_code.0, - pvf_exec_timeout(&executor_params, exec_kind), + pvf_exec_timeout(&executor_params, exec_kind.into()), persisted_validation_data.clone(), pov, executor_params, PVF_APPROVAL_EXECUTION_RETRY_DELAY, - polkadot_node_core_pvf::Priority::Critical, + exec_kind.into(), + exec_kind, ) .await, }; @@ -743,20 +873,35 @@ 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 { + if res.head_data.hash() != candidate_receipt.descriptor.para_head() { gum::info!(target: LOG_TARGET, ?para_id, "Invalid candidate (para_head)"); Ok(ValidationResult::Invalid(InvalidCandidate::ParaHeadHashMismatch)) } else { - let outputs = CandidateCommitments { - head_data: res.head_data, - upward_messages: res.upward_messages, - horizontal_messages: res.horizontal_messages, - new_validation_code: res.new_validation_code, - processed_downward_messages: res.processed_downward_messages, - hrmp_watermark: res.hrmp_watermark, + let committed_candidate_receipt = CommittedCandidateReceipt { + descriptor: candidate_receipt.descriptor.clone(), + commitments: CandidateCommitments { + head_data: res.head_data, + upward_messages: res.upward_messages, + horizontal_messages: res.horizontal_messages, + new_validation_code: res.new_validation_code, + processed_downward_messages: res.processed_downward_messages, + hrmp_watermark: res.hrmp_watermark, + }, }; - if candidate_receipt.commitments_hash != outputs.hash() { + + if candidate_receipt.commitments_hash != + committed_candidate_receipt.commitments.hash() + { gum::info!( target: LOG_TARGET, ?para_id, @@ -767,7 +912,48 @@ async fn validate_candidate_exhaustive( // invalid. Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch)) } else { - Ok(ValidationResult::Valid(outputs, (*persisted_validation_data).clone())) + let core_index = candidate_receipt.descriptor.core_index(); + + match (core_index, exec_kind) { + // Core selectors are optional for V2 descriptors, but we still check the + // descriptor core index. + ( + Some(_core_index), + PvfExecKind::Backing(_) | PvfExecKind::BackingSystemParas(_), + ) => { + let Some(claim_queue) = maybe_claim_queue else { + let error = "cannot fetch the claim queue from the runtime"; + gum::warn!( + target: LOG_TARGET, + ?relay_parent, + error + ); + + return Err(ValidationFailed(error.into())) + }; + + if let Err(err) = committed_candidate_receipt + .check_core_index(&transpose_claim_queue(claim_queue.0)) + { + gum::warn!( + target: LOG_TARGET, + ?err, + candidate_hash = ?candidate_receipt.hash(), + "Candidate core index is invalid", + ); + return Ok(ValidationResult::Invalid( + InvalidCandidate::InvalidCoreIndex, + )) + } + }, + // No checks for approvals and disputes + (_, _) => {}, + } + + Ok(ValidationResult::Valid( + committed_candidate_receipt.commitments, + (*persisted_validation_data).clone(), + )) } }, } @@ -784,6 +970,8 @@ trait ValidationBackend { pov: Arc, // The priority for the preparation job. prepare_priority: polkadot_node_core_pvf::Priority, + // The kind for the execution job. + exec_kind: PvfExecKind, ) -> Result; /// Tries executing a PVF. Will retry once if an error is encountered that may have @@ -804,6 +992,8 @@ trait ValidationBackend { retry_delay: Duration, // The priority for the preparation job. prepare_priority: polkadot_node_core_pvf::Priority, + // The kind for the execution job. + exec_kind: PvfExecKind, ) -> Result { let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); // Construct the PVF a single time, since it is an expensive operation. Cloning it is cheap. @@ -825,6 +1015,7 @@ trait ValidationBackend { pvd.clone(), pov.clone(), prepare_priority, + exec_kind, ) .await; if validation_result.is_ok() { @@ -876,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 @@ -905,6 +1101,7 @@ trait ValidationBackend { pvd.clone(), pov.clone(), prepare_priority, + exec_kind, ) .await; } @@ -916,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] @@ -929,9 +1132,13 @@ impl ValidationBackend for ValidationHost { pov: Arc, // The priority for the preparation job. prepare_priority: polkadot_node_core_pvf::Priority, + // The kind for the execution job. + exec_kind: PvfExecKind, ) -> Result { let (tx, rx) = oneshot::channel(); - if let Err(err) = self.execute_pvf(pvf, exec_timeout, pvd, pov, prepare_priority, tx).await + if let Err(err) = self + .execute_pvf(pvf, exec_timeout, pvd, pov, prepare_priority, exec_kind, tx) + .await { return Err(InternalValidationError::HostCommunication(format!( "cannot send pvf to the validation host, it might have shut down: {:?}", @@ -962,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 @@ -979,14 +1194,15 @@ fn perform_basic_checks( return Err(InvalidCandidate::ParamsTooLarge(encoded_pov_size as u64)) } - if pov_hash != candidate.pov_hash { + if pov_hash != candidate.pov_hash() { return Err(InvalidCandidate::PoVHashMismatch) } - if *validation_code_hash != candidate.validation_code_hash { + if *validation_code_hash != candidate.validation_code_hash() { return Err(InvalidCandidate::CodeHashMismatch) } + // No-op for `v2` receipts. if let Err(()) = candidate.check_collator_signature() { return Err(InvalidCandidate::BadSignature) } @@ -1023,12 +1239,12 @@ fn pvf_prep_timeout(executor_params: &ExecutorParams, kind: PvfPrepKind) -> Dura /// This should be much longer than the backing execution timeout to ensure that in the /// absence of extremely large disparities between hardware, blocks that pass backing are /// considered executable by approval checkers or dispute participants. -fn pvf_exec_timeout(executor_params: &ExecutorParams, kind: PvfExecKind) -> Duration { +fn pvf_exec_timeout(executor_params: &ExecutorParams, kind: RuntimePvfExecKind) -> Duration { if let Some(timeout) = executor_params.pvf_exec_timeout(kind) { return timeout } match kind { - PvfExecKind::Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT, - PvfExecKind::Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT, + RuntimePvfExecKind::Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT, + RuntimePvfExecKind::Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT, } } diff --git a/polkadot/node/core/candidate-validation/src/tests.rs b/polkadot/node/core/candidate-validation/src/tests.rs index 46de55e4836e..98e34a1cb4c1 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -14,9 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::{ + collections::BTreeMap, + sync::atomic::{AtomicUsize, Ordering}, +}; use super::*; +use crate::PvfExecKind; use assert_matches::assert_matches; use futures::executor; use polkadot_node_core_pvf::PrepareError; @@ -25,12 +29,18 @@ use polkadot_node_subsystem::messages::AllMessages; use polkadot_node_subsystem_util::reexports::SubsystemContext; use polkadot_overseer::ActivatedLeaf; use polkadot_primitives::{ - CoreIndex, GroupIndex, HeadData, Id as ParaId, OccupiedCoreAssumption, SessionInfo, - UpwardMessage, ValidatorId, + vstaging::{ + CandidateDescriptorV2, ClaimQueueOffset, CoreSelector, MutateDescriptorV2, UMPSignal, + UMP_SEPARATOR, + }, + CandidateDescriptor, CoreIndex, GroupIndex, HeadData, Id as ParaId, OccupiedCoreAssumption, + SessionInfo, UpwardMessage, ValidatorId, }; use polkadot_primitives_test_helpers::{ dummy_collator, dummy_collator_signature, dummy_hash, make_valid_candidate_descriptor, + make_valid_candidate_descriptor_v2, }; +use rstest::rstest; use sp_core::{sr25519::Public, testing::TaskExecutor}; use sp_keyring::Sr25519Keyring; use sp_keystore::{testing::MemoryKeystore, Keystore}; @@ -105,7 +115,8 @@ fn correctly_checks_included_assumption() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let pool = TaskExecutor::new(); let (mut ctx, mut ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< @@ -179,7 +190,8 @@ fn correctly_checks_timed_out_assumption() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let pool = TaskExecutor::new(); let (mut ctx, mut ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< @@ -251,7 +263,8 @@ fn check_is_bad_request_if_no_validation_data() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let pool = TaskExecutor::new(); let (mut ctx, mut ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< @@ -307,7 +320,8 @@ fn check_is_bad_request_if_no_validation_code() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let pool = TaskExecutor::new(); let (mut ctx, mut ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< @@ -375,7 +389,8 @@ fn check_does_not_match() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let pool = TaskExecutor::new(); let (mut ctx, mut ctx_handle) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< @@ -441,6 +456,7 @@ impl ValidationBackend for MockValidateCandidateBackend { _pvd: Arc, _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, + _exec_kind: PvfExecKind, ) -> Result { // This is expected to panic if called more times than expected, indicating an error in the // test. @@ -457,27 +473,35 @@ 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] -fn candidate_validation_ok_is_ok() { +fn session_index_checked_only_in_backing() { let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; let pov = PoV { block_data: BlockData(vec![1; 32]) }; let head_data = HeadData(vec![1, 1, 1]); let validation_code = ValidationCode(vec![2; 16]); - let descriptor = make_valid_candidate_descriptor( + let descriptor = make_valid_candidate_descriptor_v2( ParaId::from(1_u32), dummy_hash(), - validation_data.hash(), + CoreIndex(0), + 100, + dummy_hash(), pov.hash(), validation_code.hash(), head_data.hash(), dummy_hash(), - Sr25519Keyring::Alice, ); - let check = perform_basic_checks( &descriptor, validation_data.max_pov_size, @@ -506,15 +530,59 @@ fn candidate_validation_ok_is_ok() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; + // The session index is invalid + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Backing(dummy_hash()), + &Default::default(), + Default::default(), + )) + .unwrap(); + + assert_matches!(v, ValidationResult::Invalid(InvalidCandidate::InvalidSessionIndex)); + + // Approval doesn't fail since the check is ommited. let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Approval, + &Default::default(), + Default::default(), + )) + .unwrap(); + + assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.upward_messages, Vec::::new()); + assert_eq!(outputs.horizontal_messages, Vec::new()); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + assert_eq!(outputs.hrmp_watermark, 0); + assert_eq!(used_validation_data, validation_data); + }); + + // Approval doesn't fail since the check is ommited. + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data.clone(), validation_code, candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Dispute, &Default::default(), + Default::default(), )) .unwrap(); @@ -528,6 +596,323 @@ fn candidate_validation_ok_is_ok() { }); } +#[rstest] +#[case(true)] +#[case(false)] +fn candidate_validation_ok_is_ok(#[case] v2_descriptor: bool) { + let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; + + let pov = PoV { block_data: BlockData(vec![1; 32]) }; + let head_data = HeadData(vec![1, 1, 1]); + let validation_code = ValidationCode(vec![2; 16]); + + let descriptor = if v2_descriptor { + make_valid_candidate_descriptor_v2( + ParaId::from(1_u32), + dummy_hash(), + CoreIndex(1), + 1, + dummy_hash(), + pov.hash(), + validation_code.hash(), + head_data.hash(), + dummy_hash(), + ) + } else { + make_valid_candidate_descriptor( + ParaId::from(1_u32), + dummy_hash(), + validation_data.hash(), + pov.hash(), + validation_code.hash(), + head_data.hash(), + dummy_hash(), + Sr25519Keyring::Alice, + ) + .into() + }; + + let check = perform_basic_checks( + &descriptor, + validation_data.max_pov_size, + &pov, + &validation_code.hash(), + ); + assert!(check.is_ok()); + + let mut validation_result = WasmValidationResult { + head_data, + new_validation_code: Some(vec![2, 2, 2].into()), + upward_messages: Default::default(), + horizontal_messages: Default::default(), + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + + if v2_descriptor { + validation_result.upward_messages.force_push(UMP_SEPARATOR); + validation_result + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(1)).encode()); + } + + let commitments = CandidateCommitments { + head_data: validation_result.head_data.clone(), + upward_messages: validation_result.upward_messages.clone(), + horizontal_messages: validation_result.horizontal_messages.clone(), + new_validation_code: validation_result.new_validation_code.clone(), + processed_downward_messages: validation_result.processed_downward_messages, + hrmp_watermark: validation_result.hrmp_watermark, + }; + + let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; + let mut cq = BTreeMap::new(); + let _ = cq.insert(CoreIndex(0), vec![1.into(), 2.into()].into()); + let _ = cq.insert(CoreIndex(1), vec![1.into(), 1.into()].into()); + + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), + validation_data.clone(), + validation_code, + candidate_receipt, + Arc::new(pov), + ExecutorParams::default(), + PvfExecKind::Backing(dummy_hash()), + &Default::default(), + Some(ClaimQueueSnapshot(cq)), + )) + .unwrap(); + + assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.upward_messages, commitments.upward_messages); + assert_eq!(outputs.horizontal_messages, Vec::new()); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + assert_eq!(outputs.hrmp_watermark, 0); + assert_eq!(used_validation_data, validation_data); + }); +} + +#[test] +fn invalid_session_or_core_index() { + let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; + + let pov = PoV { block_data: BlockData(vec![1; 32]) }; + let head_data = HeadData(vec![1, 1, 1]); + let validation_code = ValidationCode(vec![2; 16]); + + let descriptor = make_valid_candidate_descriptor_v2( + ParaId::from(1_u32), + dummy_hash(), + CoreIndex(1), + 100, + dummy_hash(), + pov.hash(), + validation_code.hash(), + head_data.hash(), + dummy_hash(), + ); + + let check = perform_basic_checks( + &descriptor, + validation_data.max_pov_size, + &pov, + &validation_code.hash(), + ); + assert!(check.is_ok()); + + let mut validation_result = WasmValidationResult { + head_data, + new_validation_code: Some(vec![2, 2, 2].into()), + upward_messages: Default::default(), + horizontal_messages: Default::default(), + processed_downward_messages: 0, + hrmp_watermark: 0, + }; + + validation_result.upward_messages.force_push(UMP_SEPARATOR); + validation_result + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(1), ClaimQueueOffset(0)).encode()); + + let commitments = CandidateCommitments { + head_data: validation_result.head_data.clone(), + upward_messages: validation_result.upward_messages.clone(), + horizontal_messages: validation_result.horizontal_messages.clone(), + new_validation_code: validation_result.new_validation_code.clone(), + processed_downward_messages: validation_result.processed_downward_messages, + hrmp_watermark: validation_result.hrmp_watermark, + }; + + let mut candidate_receipt = + CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; + + let err = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Backing(dummy_hash()), + &Default::default(), + Default::default(), + )) + .unwrap(); + + assert_matches!(err, ValidationResult::Invalid(InvalidCandidate::InvalidSessionIndex)); + + let err = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::BackingSystemParas(dummy_hash()), + &Default::default(), + Default::default(), + )) + .unwrap(); + + assert_matches!(err, ValidationResult::Invalid(InvalidCandidate::InvalidSessionIndex)); + + candidate_receipt.descriptor.set_session_index(1); + + let result = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Backing(dummy_hash()), + &Default::default(), + Some(Default::default()), + )) + .unwrap(); + assert_matches!(result, ValidationResult::Invalid(InvalidCandidate::InvalidCoreIndex)); + + let result = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::BackingSystemParas(dummy_hash()), + &Default::default(), + Some(Default::default()), + )) + .unwrap(); + assert_matches!(result, ValidationResult::Invalid(InvalidCandidate::InvalidCoreIndex)); + + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Approval, + &Default::default(), + Default::default(), + )) + .unwrap(); + + // Validation doesn't fail for approvals, core/session index is not checked. + assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.upward_messages, commitments.upward_messages); + assert_eq!(outputs.horizontal_messages, Vec::new()); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + assert_eq!(outputs.hrmp_watermark, 0); + assert_eq!(used_validation_data, validation_data); + }); + + // Dispute check passes because we don't check core or session index + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Dispute, + &Default::default(), + Default::default(), + )) + .unwrap(); + + // Validation doesn't fail for approvals, core/session index is not checked. + assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.upward_messages, commitments.upward_messages); + assert_eq!(outputs.horizontal_messages, Vec::new()); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + assert_eq!(outputs.hrmp_watermark, 0); + assert_eq!(used_validation_data, validation_data); + }); + + // Populate claim queue. + let mut cq = BTreeMap::new(); + let _ = cq.insert(CoreIndex(0), vec![1.into(), 2.into()].into()); + let _ = cq.insert(CoreIndex(1), vec![1.into(), 2.into()].into()); + + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::Backing(dummy_hash()), + &Default::default(), + Some(ClaimQueueSnapshot(cq.clone())), + )) + .unwrap(); + + assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.upward_messages, commitments.upward_messages); + assert_eq!(outputs.horizontal_messages, Vec::new()); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + assert_eq!(outputs.hrmp_watermark, 0); + assert_eq!(used_validation_data, validation_data); + }); + + let v = executor::block_on(validate_candidate_exhaustive( + Some(1), + MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result.clone())), + validation_data.clone(), + validation_code.clone(), + candidate_receipt.clone(), + Arc::new(pov.clone()), + ExecutorParams::default(), + PvfExecKind::BackingSystemParas(dummy_hash()), + &Default::default(), + Some(ClaimQueueSnapshot(cq)), + )) + .unwrap(); + + assert_matches!(v, ValidationResult::Valid(outputs, used_validation_data) => { + assert_eq!(outputs.head_data, HeadData(vec![1, 1, 1])); + assert_eq!(outputs.upward_messages, commitments.upward_messages); + assert_eq!(outputs.horizontal_messages, Vec::new()); + assert_eq!(outputs.new_validation_code, Some(vec![2, 2, 2].into())); + assert_eq!(outputs.hrmp_watermark, 0); + assert_eq!(used_validation_data, validation_data); + }); +} + #[test] fn candidate_validation_bad_return_is_invalid() { let validation_data = PersistedValidationData { max_pov_size: 1024, ..Default::default() }; @@ -544,7 +929,8 @@ fn candidate_validation_bad_return_is_invalid() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let check = perform_basic_checks( &descriptor, @@ -557,6 +943,7 @@ fn candidate_validation_bad_return_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result(Err(ValidationError::Invalid( WasmInvalidCandidate::HardTimeout, ))), @@ -565,8 +952,9 @@ fn candidate_validation_bad_return_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), + Default::default(), )) .unwrap(); @@ -578,7 +966,7 @@ fn perform_basic_checks_on_valid_candidate( validation_code: &ValidationCode, validation_data: &PersistedValidationData, head_data_hash: Hash, -) -> CandidateDescriptor { +) -> CandidateDescriptorV2 { let descriptor = make_valid_candidate_descriptor( ParaId::from(1_u32), dummy_hash(), @@ -588,7 +976,8 @@ fn perform_basic_checks_on_valid_candidate( head_data_hash, head_data_hash, Sr25519Keyring::Alice, - ); + ) + .into(); let check = perform_basic_checks( &descriptor, @@ -637,6 +1026,7 @@ fn candidate_validation_one_ambiguous_error_is_valid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result_list(vec![ Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), Ok(validation_result), @@ -648,6 +1038,7 @@ fn candidate_validation_one_ambiguous_error_is_valid() { ExecutorParams::default(), PvfExecKind::Approval, &Default::default(), + Default::default(), )) .unwrap(); @@ -678,6 +1069,7 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result_list(vec![ Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), Err(ValidationError::PossiblyInvalid(PossiblyInvalidError::AmbiguousWorkerDeath)), @@ -689,6 +1081,7 @@ fn candidate_validation_multiple_ambiguous_errors_is_invalid() { ExecutorParams::default(), PvfExecKind::Approval, &Default::default(), + Default::default(), )) .unwrap(); @@ -717,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. @@ -751,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. @@ -782,7 +1175,8 @@ fn candidate_validation_retry_on_error_helper( dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let check = perform_basic_checks( &descriptor, @@ -795,6 +1189,7 @@ fn candidate_validation_retry_on_error_helper( let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; return executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result_list(mock_errors), validation_data, validation_code, @@ -803,6 +1198,7 @@ fn candidate_validation_retry_on_error_helper( ExecutorParams::default(), exec_kind, &Default::default(), + Default::default(), )) } @@ -822,7 +1218,8 @@ fn candidate_validation_timeout_is_internal_error() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let check = perform_basic_checks( &descriptor, @@ -835,6 +1232,7 @@ fn candidate_validation_timeout_is_internal_error() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: Hash::zero() }; let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result(Err(ValidationError::Invalid( WasmInvalidCandidate::HardTimeout, ))), @@ -843,8 +1241,9 @@ fn candidate_validation_timeout_is_internal_error() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), + Default::default(), )); assert_matches!(v, Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))); @@ -867,9 +1266,11 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() { head_data.hash(), dummy_hash(), Sr25519Keyring::Alice, - ), + ) + .into(), commitments_hash: Hash::zero(), - }; + } + .into(); // This will result in different commitments for this candidate. let validation_result = WasmValidationResult { @@ -882,14 +1283,16 @@ fn candidate_validation_commitment_hash_mismatch_is_invalid() { }; let result = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), + Default::default(), )) .unwrap(); @@ -913,7 +1316,8 @@ fn candidate_validation_code_mismatch_is_invalid() { dummy_hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let check = perform_basic_checks( &descriptor, @@ -932,6 +1336,7 @@ fn candidate_validation_code_mismatch_is_invalid() { >(pool.clone()); let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result(Err(ValidationError::Invalid( WasmInvalidCandidate::HardTimeout, ))), @@ -940,8 +1345,9 @@ fn candidate_validation_code_mismatch_is_invalid() { candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), + Default::default(), )) .unwrap(); @@ -968,7 +1374,8 @@ fn compressed_code_works() { head_data.hash(), dummy_hash(), Sr25519Keyring::Alice, - ); + ) + .into(); let validation_result = WasmValidationResult { head_data, @@ -991,14 +1398,16 @@ fn compressed_code_works() { let candidate_receipt = CandidateReceipt { descriptor, commitments_hash: commitments.hash() }; let v = executor::block_on(validate_candidate_exhaustive( + Some(1), MockValidateCandidateBackend::with_hardcoded_result(Ok(validation_result)), validation_data, validation_code, candidate_receipt, Arc::new(pov), ExecutorParams::default(), - PvfExecKind::Backing, + PvfExecKind::Backing(dummy_hash()), &Default::default(), + Default::default(), )); assert_matches!(v, Ok(ValidationResult::Valid(_, _))); @@ -1023,6 +1432,7 @@ impl ValidationBackend for MockPreCheckBackend { _pvd: Arc, _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, + _exec_kind: PvfExecKind, ) -> Result { unreachable!() } @@ -1034,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] @@ -1177,6 +1595,7 @@ impl ValidationBackend for MockHeadsUp { _pvd: Arc, _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, + _exec_kind: PvfExecKind, ) -> Result { unreachable!() } @@ -1189,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 { @@ -1235,7 +1662,8 @@ fn dummy_candidate_backed( signature: dummy_collator_signature(), para_head: zeros, validation_code_hash, - }; + } + .into(); CandidateEvent::CandidateBacked( CandidateReceipt { descriptor, commitments_hash: zeros }, diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index eb4600b235b9..344b66af1933 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -37,6 +37,7 @@ polkadot-primitives-test-helpers = { workspace = true } futures-timer = { workspace = true } sp-application-crypto = { 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/dispute-coordinator/src/db/v1.rs b/polkadot/node/core/dispute-coordinator/src/db/v1.rs index 0101791550ee..962dfcbbcfac 100644 --- a/polkadot/node/core/dispute-coordinator/src/db/v1.rs +++ b/polkadot/node/core/dispute-coordinator/src/db/v1.rs @@ -25,8 +25,9 @@ use polkadot_node_primitives::DisputeStatus; use polkadot_node_subsystem_util::database::{DBTransaction, Database}; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, Hash, InvalidDisputeStatementKind, SessionIndex, - ValidDisputeStatementKind, ValidatorIndex, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, Hash, + InvalidDisputeStatementKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, + ValidatorSignature, }; use std::sync::Arc; @@ -377,7 +378,9 @@ mod tests { use super::*; use polkadot_node_primitives::DISPUTE_WINDOW; use polkadot_primitives::{Hash, Id as ParaId}; - use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; + use polkadot_primitives_test_helpers::{ + dummy_candidate_receipt, dummy_candidate_receipt_v2, dummy_hash, + }; fn make_db() -> DbBackend { let db = kvdb_memorydb::create(1); @@ -403,7 +406,7 @@ mod tests { session, candidate_hash, CandidateVotes { - candidate_receipt: dummy_candidate_receipt(dummy_hash()), + candidate_receipt: dummy_candidate_receipt_v2(dummy_hash()), valid: Vec::new(), invalid: Vec::new(), }, @@ -495,7 +498,7 @@ mod tests { 1, CandidateHash(Hash::repeat_byte(1)), CandidateVotes { - candidate_receipt: dummy_candidate_receipt(dummy_hash()), + candidate_receipt: dummy_candidate_receipt_v2(dummy_hash()), valid: Vec::new(), invalid: Vec::new(), }, @@ -508,7 +511,7 @@ mod tests { let mut receipt = dummy_candidate_receipt(dummy_hash()); receipt.descriptor.para_id = ParaId::from(5_u32); - receipt + receipt.into() }, valid: Vec::new(), invalid: Vec::new(), @@ -532,7 +535,7 @@ mod tests { .unwrap() .candidate_receipt .descriptor - .para_id, + .para_id(), ParaId::from(5), ); @@ -556,7 +559,7 @@ mod tests { .unwrap() .candidate_receipt .descriptor - .para_id, + .para_id(), ParaId::from(5), ); } @@ -571,13 +574,13 @@ mod tests { 1, CandidateHash(Hash::repeat_byte(1)), CandidateVotes { - candidate_receipt: dummy_candidate_receipt(Hash::random()), + candidate_receipt: dummy_candidate_receipt_v2(Hash::random()), valid: Vec::new(), invalid: Vec::new(), }, ); - let receipt = dummy_candidate_receipt(dummy_hash()); + let receipt = dummy_candidate_receipt_v2(dummy_hash()); overlay_db.write_candidate_votes( 1, @@ -621,7 +624,7 @@ mod tests { let very_recent = current_session - 1; let blank_candidate_votes = || CandidateVotes { - candidate_receipt: dummy_candidate_receipt(dummy_hash()), + candidate_receipt: dummy_candidate_receipt_v2(dummy_hash()), valid: Vec::new(), invalid: Vec::new(), }; diff --git a/polkadot/node/core/dispute-coordinator/src/import.rs b/polkadot/node/core/dispute-coordinator/src/import.rs index d3a4625f0d24..4263dda54b9b 100644 --- a/polkadot/node/core/dispute-coordinator/src/import.rs +++ b/polkadot/node/core/dispute-coordinator/src/import.rs @@ -34,9 +34,9 @@ use polkadot_node_primitives::{ use polkadot_node_subsystem::overseer; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, DisputeStatement, ExecutorParams, Hash, IndexedVec, - SessionIndex, SessionInfo, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, - ValidatorPair, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, DisputeStatement, + ExecutorParams, Hash, IndexedVec, SessionIndex, SessionInfo, ValidDisputeStatementKind, + ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 9cf9047b7273..7fc22d5904c5 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -44,9 +44,10 @@ use polkadot_node_subsystem_util::runtime::{ self, key_ownership_proof, submit_report_dispute_lost, RuntimeInfo, }; use polkadot_primitives::{ - slashing, BlockNumber, CandidateHash, CandidateReceipt, CompactStatement, DisputeStatement, - DisputeStatementSet, Hash, ScrapedOnChainVotes, SessionIndex, ValidDisputeStatementKind, - ValidatorId, ValidatorIndex, + slashing, + vstaging::{CandidateReceiptV2 as CandidateReceipt, ScrapedOnChainVotes}, + BlockNumber, CandidateHash, CompactStatement, DisputeStatement, DisputeStatementSet, Hash, + SessionIndex, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, }; use schnellru::{LruMap, UnlimitedCompact}; @@ -607,7 +608,7 @@ impl Initialized { // the new active leaf as if we received them via gossip. for (candidate_receipt, backers) in backing_validators_per_candidate { // Obtain the session info, for sake of `ValidatorId`s - let relay_parent = candidate_receipt.descriptor.relay_parent; + let relay_parent = candidate_receipt.descriptor.relay_parent(); let session_info = match self .runtime_info .get_session_info_by_index(ctx.sender(), relay_parent, session) @@ -958,9 +959,9 @@ impl Initialized { let votes_in_db = overlay_db.load_candidate_votes(session, &candidate_hash)?; let relay_parent = match &candidate_receipt { MaybeCandidateReceipt::Provides(candidate_receipt) => - candidate_receipt.descriptor().relay_parent, + candidate_receipt.descriptor().relay_parent(), MaybeCandidateReceipt::AssumeBackingVotePresent(candidate_hash) => match &votes_in_db { - Some(votes) => votes.candidate_receipt.descriptor().relay_parent, + Some(votes) => votes.candidate_receipt.descriptor().relay_parent(), None => { gum::warn!( target: LOG_TARGET, @@ -1451,7 +1452,7 @@ impl Initialized { ctx, &mut self.runtime_info, session, - candidate_receipt.descriptor.relay_parent, + candidate_receipt.descriptor.relay_parent(), self.offchain_disabled_validators.iter(session), ) .await diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index 84408eb96305..3078ada5d53f 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -46,7 +46,7 @@ use polkadot_node_subsystem_util::{ runtime::{Config as RuntimeInfoConfig, RuntimeInfo}, }; use polkadot_primitives::{ - DisputeStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorIndex, + vstaging::ScrapedOnChainVotes, DisputeStatement, SessionIndex, SessionInfo, ValidatorIndex, }; use crate::{ diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs index b58ce570f8ff..770c44f7d609 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs @@ -27,12 +27,13 @@ use futures_timer::Delay; use polkadot_node_primitives::ValidationResult; use polkadot_node_subsystem::{ - messages::{AvailabilityRecoveryMessage, CandidateValidationMessage}, + messages::{AvailabilityRecoveryMessage, CandidateValidationMessage, PvfExecKind}, overseer, ActiveLeavesUpdate, RecoveryError, }; use polkadot_node_subsystem_util::runtime::get_validation_code_by_hash; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, Hash, PvfExecKind, SessionIndex, + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, Hash, + SessionIndex, }; use crate::LOG_TARGET; @@ -350,7 +351,7 @@ async fn participate( let validation_code = match get_validation_code_by_hash( &mut sender, block_hash, - req.candidate_receipt().descriptor.validation_code_hash, + req.candidate_receipt().descriptor.validation_code_hash(), ) .await { @@ -359,7 +360,7 @@ async fn participate( gum::warn!( target: LOG_TARGET, "Validation code unavailable for code hash {:?} in the state of block {:?}", - req.candidate_receipt().descriptor.validation_code_hash, + req.candidate_receipt().descriptor.validation_code_hash(), block_hash, ); @@ -387,7 +388,7 @@ async fn participate( candidate_receipt: req.candidate_receipt().clone(), pov: available_data.pov, executor_params: req.executor_params(), - exec_kind: PvfExecKind::Approval, + exec_kind: PvfExecKind::Dispute, response_sender: validation_tx, }) .await; diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs index d9e86def168c..4d317d38590a 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/mod.rs @@ -22,7 +22,8 @@ use std::{ use futures::channel::oneshot; use polkadot_node_subsystem::{messages::ChainApiMessage, overseer}; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex, + vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, ExecutorParams, + Hash, SessionIndex, }; use crate::{ @@ -405,7 +406,7 @@ impl CandidateComparator { candidate: &CandidateReceipt, ) -> FatalResult { let candidate_hash = candidate.hash(); - let n = get_block_number(sender, candidate.descriptor().relay_parent).await?; + let n = get_block_number(sender, candidate.descriptor().relay_parent()).await?; if n.is_none() { gum::warn!( diff --git a/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs index 9176d00b2f5c..a25387a7eb5a 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/queues/tests.rs @@ -17,13 +17,13 @@ use crate::{metrics::Metrics, ParticipationPriority}; use assert_matches::assert_matches; use polkadot_primitives::{BlockNumber, Hash}; -use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; +use polkadot_primitives_test_helpers::{dummy_candidate_receipt_v2, dummy_hash}; use super::{CandidateComparator, ParticipationRequest, QueueError, Queues}; /// Make a `ParticipationRequest` based on the given commitments hash. fn make_participation_request(hash: Hash) -> ParticipationRequest { - let mut receipt = dummy_candidate_receipt(dummy_hash()); + let mut receipt = dummy_candidate_receipt_v2(dummy_hash()); // make it differ: receipt.commitments_hash = hash; let request_timer = Metrics::default().time_participation_pipeline(); diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs index a80553828ac6..23f7984965b3 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs @@ -26,7 +26,7 @@ use codec::Encode; use polkadot_node_primitives::{AvailableData, BlockData, InvalidCandidate, PoV}; use polkadot_node_subsystem::{ messages::{ - AllMessages, ChainApiMessage, DisputeCoordinatorMessage, RuntimeApiMessage, + AllMessages, ChainApiMessage, DisputeCoordinatorMessage, PvfExecKind, RuntimeApiMessage, RuntimeApiRequest, }, ActiveLeavesUpdate, SpawnGlue, @@ -68,7 +68,8 @@ async fn participate_with_commitments_hash( let mut receipt = dummy_candidate_receipt_bad_sig(dummy_hash(), dummy_hash()); receipt.commitments_hash = commitments_hash; receipt - }; + } + .into(); let session = 1; let request_timer = participation.metrics.time_participation_pipeline(); @@ -116,7 +117,7 @@ pub async fn participation_full_happy_path( ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { candidate_receipt, exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { if expected_commitments_hash != candidate_receipt.commitments_hash { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); } else { @@ -450,7 +451,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, "overseer did not receive candidate validation message", @@ -487,7 +488,7 @@ fn cast_invalid_vote_if_commitments_dont_match() { ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, "overseer did not receive candidate validation message", @@ -524,7 +525,7 @@ fn cast_valid_vote_if_validation_passes() { ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { response_sender.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, "overseer did not receive candidate validation message", diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs index 4c45d9dcc220..9aaad9d1c528 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs @@ -28,8 +28,9 @@ use polkadot_node_subsystem_util::runtime::{ self, get_candidate_events, get_on_chain_votes, get_unapplied_slashes, }; use polkadot_primitives::{ - slashing::PendingSlashes, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, Hash, - ScrapedOnChainVotes, SessionIndex, + slashing::PendingSlashes, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt, ScrapedOnChainVotes}, + BlockNumber, CandidateHash, Hash, SessionIndex, }; use crate::{ diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs index ed2400387ef7..fe04193014c6 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/tests.rs @@ -36,8 +36,9 @@ use polkadot_node_subsystem_test_helpers::{ }; use polkadot_node_subsystem_util::{reexports::SubsystemContext, TimeoutExt}; use polkadot_primitives::{ - BlakeTwo256, BlockNumber, CandidateDescriptor, CandidateEvent, CandidateReceipt, CoreIndex, - GroupIndex, Hash, HashT, HeadData, Id as ParaId, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt}, + BlakeTwo256, BlockNumber, CandidateDescriptor, CoreIndex, GroupIndex, Hash, HashT, HeadData, + Id as ParaId, }; use polkadot_primitives_test_helpers::{dummy_collator, dummy_collator_signature, dummy_hash}; @@ -135,7 +136,8 @@ fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { signature: dummy_collator_signature(), para_head: zeros, validation_code_hash: zeros.into(), - }; + } + .into(); CandidateReceipt { descriptor, commitments_hash: zeros } } diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 48762a1d80be..9383f71804ed 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -60,13 +60,18 @@ use polkadot_node_subsystem_test_helpers::{ make_buffered_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; use polkadot_primitives::{ - ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, HeadData, - Header, IndexedVec, MultiDisputeStatementSet, NodeFeatures, ScrapedOnChainVotes, SessionIndex, - SessionInfo, SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, - ValidatorSignature, + vstaging::{ + CandidateEvent, CandidateReceiptV2 as CandidateReceipt, MutateDescriptorV2, + ScrapedOnChainVotes, + }, + ApprovalVote, BlockNumber, CandidateCommitments, CandidateHash, CoreIndex, DisputeStatement, + ExecutorParams, GroupIndex, Hash, HeadData, Header, IndexedVec, MultiDisputeStatementSet, + NodeFeatures, SessionIndex, SessionInfo, SigningContext, ValidDisputeStatementKind, + ValidatorId, ValidatorIndex, ValidatorSignature, +}; +use polkadot_primitives_test_helpers::{ + dummy_candidate_receipt_v2_bad_sig, dummy_digest, dummy_hash, }; -use polkadot_primitives_test_helpers::{dummy_candidate_receipt_bad_sig, dummy_digest, dummy_hash}; use crate::{ backend::Backend, @@ -648,11 +653,11 @@ fn make_valid_candidate_receipt() -> CandidateReceipt { } fn make_invalid_candidate_receipt() -> CandidateReceipt { - dummy_candidate_receipt_bad_sig(Default::default(), Some(Default::default())) + dummy_candidate_receipt_v2_bad_sig(Default::default(), Some(Default::default())) } fn make_another_valid_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { - let mut candidate_receipt = dummy_candidate_receipt_bad_sig(relay_parent, dummy_hash()); + let mut candidate_receipt = dummy_candidate_receipt_v2_bad_sig(relay_parent, dummy_hash()); candidate_receipt.commitments_hash = CandidateCommitments::default().hash(); candidate_receipt } @@ -3858,14 +3863,15 @@ fn participation_requests_reprioritized_for_newly_included() { for repetition in 1..=3u8 { // Building candidate receipts let mut candidate_receipt = make_valid_candidate_receipt(); - candidate_receipt.descriptor.pov_hash = Hash::from( + candidate_receipt.descriptor.set_pov_hash(Hash::from( [repetition; 32], // Altering this receipt so its hash will be changed - ); + )); // Set consecutive parents (starting from zero). They will order the candidates for // participation. let parent_block_num: BlockNumber = repetition as BlockNumber - 1; - candidate_receipt.descriptor.relay_parent = - *test_state.block_num_to_header.get(&parent_block_num).unwrap(); + candidate_receipt.descriptor.set_relay_parent( + *test_state.block_num_to_header.get(&parent_block_num).unwrap(), + ); receipts.push(candidate_receipt.clone()); } diff --git a/polkadot/node/core/parachains-inherent/src/lib.rs b/polkadot/node/core/parachains-inherent/src/lib.rs index 1de3cab32bed..5f3092f6a881 100644 --- a/polkadot/node/core/parachains-inherent/src/lib.rs +++ b/polkadot/node/core/parachains-inherent/src/lib.rs @@ -29,7 +29,7 @@ use futures::{select, FutureExt}; use polkadot_node_subsystem::{ errors::SubsystemError, messages::ProvisionerMessage, overseer::Handle, }; -use polkadot_primitives::{Block, Hash, InherentData as ParachainsInherentData}; +use polkadot_primitives::{vstaging::InherentData as ParachainsInherentData, Block, Hash}; use std::{sync::Arc, time}; pub(crate) const LOG_TARGET: &str = "parachain::parachains-inherent"; diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 705014e67a05..5629e4ef7fbe 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -23,6 +23,7 @@ polkadot-node-subsystem-util = { workspace = true, default-features = true } 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 } rand = { 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 b060897d4391..ded0a3ab73b2 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/mod.rs @@ -136,8 +136,9 @@ use polkadot_node_subsystem_util::inclusion_emulator::{ ProspectiveCandidate, RelayChainBlockInfo, }; use polkadot_primitives::{ - BlockNumber, CandidateCommitments, CandidateHash, CommittedCandidateReceipt, Hash, HeadData, - PersistedValidationData, ValidationCodeHash, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, BlockNumber, + CandidateCommitments, CandidateHash, Hash, HeadData, PersistedValidationData, + ValidationCodeHash, }; use thiserror::Error; @@ -371,7 +372,8 @@ impl CandidateEntry { persisted_validation_data: PersistedValidationData, state: CandidateState, ) -> Result { - if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash { + if persisted_validation_data.hash() != candidate.descriptor.persisted_validation_data_hash() + { return Err(CandidateEntryError::PersistedValidationDataMismatch) } @@ -386,13 +388,13 @@ impl CandidateEntry { candidate_hash, parent_head_data_hash, output_head_data_hash, - relay_parent: candidate.descriptor.relay_parent, + relay_parent: candidate.descriptor.relay_parent(), state, candidate: Arc::new(ProspectiveCandidate { commitments: candidate.commitments, persisted_validation_data, - pov_hash: candidate.descriptor.pov_hash, - validation_code_hash: candidate.descriptor.validation_code_hash, + pov_hash: candidate.descriptor.pov_hash(), + validation_code_hash: candidate.descriptor.validation_code_hash(), }), }) } @@ -407,8 +409,8 @@ impl HypotheticalOrConcreteCandidate for CandidateEntry { Some(&self.candidate.persisted_validation_data) } - fn validation_code_hash(&self) -> Option<&ValidationCodeHash> { - Some(&self.candidate.validation_code_hash) + fn validation_code_hash(&self) -> Option { + Some(self.candidate.validation_code_hash) } fn parent_head_data_hash(&self) -> Hash { @@ -628,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); @@ -1090,7 +1092,7 @@ impl FragmentChain { &relay_parent, &constraints, commitments, - validation_code_hash, + &validation_code_hash, pvd, ) .map_err(Error::CheckAgainstConstraints)?; 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 3332cbeb03cb..624dd74132c1 100644 --- a/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/fragment_chain/tests.rs @@ -18,7 +18,8 @@ use super::*; use assert_matches::assert_matches; use polkadot_node_subsystem_util::inclusion_emulator::InboundHrmpLimitations; use polkadot_primitives::{ - BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData, Id as ParaId, + vstaging::MutateDescriptorV2, BlockNumber, CandidateCommitments, CandidateDescriptor, HeadData, + Id as ParaId, }; use polkadot_primitives_test_helpers as test_helpers; use rand::{seq::SliceRandom, thread_rng}; @@ -70,10 +71,11 @@ 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(), - }, + } + .into(), commitments: CandidateCommitments { upward_messages: Default::default(), horizontal_messages: Default::default(), @@ -283,7 +285,7 @@ fn candidate_storage_methods() { candidate.commitments.head_data = HeadData(vec![1; 10]); let mut pvd = pvd.clone(); pvd.parent_head = HeadData(vec![1; 10]); - candidate.descriptor.persisted_validation_data_hash = pvd.hash(); + candidate.descriptor.set_persisted_validation_data_hash(pvd.hash()); assert_matches!( CandidateEntry::new_seconded(candidate_hash, candidate, pvd), Err(CandidateEntryError::ZeroLengthCycle) @@ -291,7 +293,7 @@ fn candidate_storage_methods() { } assert!(!storage.contains(&candidate_hash)); assert_eq!(storage.possible_backed_para_children(&parent_head_hash).count(), 0); - assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); + assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head()), None); assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); // Add a valid candidate. @@ -305,9 +307,9 @@ fn candidate_storage_methods() { storage.add_candidate_entry(candidate_entry.clone()).unwrap(); assert!(storage.contains(&candidate_hash)); assert_eq!(storage.possible_backed_para_children(&parent_head_hash).count(), 0); - assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head).count(), 0); + assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head()).count(), 0); assert_eq!( - storage.head_data_by_hash(&candidate.descriptor.para_head).unwrap(), + storage.head_data_by_hash(&candidate.descriptor.para_head()).unwrap(), &candidate.commitments.head_data ); assert_eq!(storage.head_data_by_hash(&parent_head_hash).unwrap(), &pvd.parent_head); @@ -323,7 +325,7 @@ fn candidate_storage_methods() { .collect::>(), vec![candidate_hash] ); - assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head).count(), 0); + assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head()).count(), 0); // Re-adding a candidate fails. assert_matches!( @@ -339,7 +341,7 @@ fn candidate_storage_methods() { storage.remove_candidate(&candidate_hash); assert!(!storage.contains(&candidate_hash)); assert_eq!(storage.possible_backed_para_children(&parent_head_hash).count(), 0); - assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head), None); + assert_eq!(storage.head_data_by_hash(&candidate.descriptor.para_head()), None); assert_eq!(storage.head_data_by_hash(&parent_head_hash), None); storage @@ -354,7 +356,7 @@ fn candidate_storage_methods() { .collect::>(), vec![candidate_hash] ); - assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head).count(), 0); + assert_eq!(storage.possible_backed_para_children(&candidate.descriptor.para_head()).count(), 0); // Now add a second candidate in Seconded state. This will be a fork. let (pvd_2, candidate_2) = make_committed_candidate( @@ -1163,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]); @@ -1183,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 b8b5f159e71c..92aea8509f8c 100644 --- a/polkadot/node/core/prospective-parachains/src/lib.rs +++ b/polkadot/node/core/prospective-parachains/src/lib.rs @@ -49,9 +49,11 @@ use polkadot_node_subsystem_util::{ runtime::{fetch_claim_queue, prospective_parachains_mode, ProspectiveParachainsMode}, }; use polkadot_primitives::{ - async_backing::CandidatePendingAvailability, BlockNumber, CandidateHash, - CommittedCandidateReceipt, CoreState, Hash, HeadData, Header, Id as ParaId, - PersistedValidationData, + vstaging::{ + async_backing::CandidatePendingAvailability, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + }, + BlockNumber, CandidateHash, Hash, HeadData, Header, Id as ParaId, PersistedValidationData, }; use crate::{ @@ -453,12 +455,13 @@ async fn preprocess_candidates_pending_availability( for (i, pending) in pending_availability.into_iter().enumerate() { let Some(relay_parent) = - fetch_block_info(ctx, cache, pending.descriptor.relay_parent).await? + fetch_block_info(ctx, cache, pending.descriptor.relay_parent()).await? else { + let para_id = pending.descriptor.para_id(); gum::debug!( target: LOG_TARGET, ?pending.candidate_hash, - ?pending.descriptor.para_id, + ?para_id, index = ?i, ?expected_count, "Had to stop processing pending candidates early due to missing info.", @@ -521,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. @@ -533,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, @@ -552,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, @@ -577,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( @@ -776,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 ) }, @@ -789,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/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index 14a093239e8e..3f1eaa4e41ed 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -25,9 +25,12 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - async_backing::{AsyncBackingParams, BackingState, Constraints, InboundHrmpLimitations}, - CommittedCandidateReceipt, CoreIndex, HeadData, Header, PersistedValidationData, ScheduledCore, - ValidationCodeHash, + async_backing::{AsyncBackingParams, Constraints, InboundHrmpLimitations}, + vstaging::{ + async_backing::BackingState, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, + MutateDescriptorV2, + }, + CoreIndex, HeadData, Header, PersistedValidationData, ScheduledCore, ValidationCodeHash, }; use polkadot_primitives_test_helpers::make_candidate; use rstest::rstest; @@ -393,15 +396,15 @@ async fn handle_leaf_activation( ); for pending in pending_availability { - if !used_relay_parents.contains(&pending.descriptor.relay_parent) { + if !used_relay_parents.contains(&pending.descriptor.relay_parent()) { send_block_header( virtual_overseer, - pending.descriptor.relay_parent, + pending.descriptor.relay_parent(), pending.relay_parent_number, ) .await; - used_relay_parents.insert(pending.descriptor.relay_parent); + used_relay_parents.insert(pending.descriptor.relay_parent()); } } } @@ -436,7 +439,7 @@ async fn introduce_seconded_candidate( pvd: PersistedValidationData, ) { let req = IntroduceSecondedCandidateRequest { - candidate_para: candidate.descriptor().para_id, + candidate_para: candidate.descriptor.para_id(), candidate_receipt: candidate, persisted_validation_data: pvd, }; @@ -455,7 +458,7 @@ async fn introduce_seconded_candidate_failed( pvd: PersistedValidationData, ) { let req = IntroduceSecondedCandidateRequest { - candidate_para: candidate.descriptor().para_id, + candidate_para: candidate.descriptor.para_id(), candidate_receipt: candidate, persisted_validation_data: pvd, }; @@ -476,7 +479,7 @@ async fn back_candidate( virtual_overseer .send(overseer::FromOrchestra::Communication { msg: ProspectiveParachainsMessage::CandidateBacked( - candidate.descriptor.para_id, + candidate.descriptor.para_id(), candidate_hash, ), }) @@ -568,7 +571,7 @@ macro_rules! make_and_back_candidate { $test_state.validation_code_hash, ); // Set a field to make this candidate unique. - candidate.descriptor.para_head = Hash::from_low_u64_le($index); + candidate.descriptor.set_para_head(Hash::from_low_u64_le($index)); let candidate_hash = candidate.hash(); introduce_seconded_candidate(&mut $virtual_overseer, candidate.clone(), pvd).await; back_candidate(&mut $virtual_overseer, &candidate, candidate_hash).await; @@ -1378,7 +1381,7 @@ fn check_backable_query_single_candidate() { test_state.validation_code_hash, ); // Set a field to make this candidate unique. - candidate_b.descriptor.para_head = Hash::from_low_u64_le(1000); + candidate_b.descriptor.set_para_head(Hash::from_low_u64_le(1000)); let candidate_hash_b = candidate_b.hash(); // Introduce candidates. diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 5869e494c70f..64a598b420f7 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -27,4 +27,6 @@ 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"] } + rstest = { workspace = true } diff --git a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs index ecb7aac78396..8c0d478b67df 100644 --- a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs +++ b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/tests.rs @@ -427,7 +427,7 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 80 / 100; let session_idx = 0; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); @@ -445,7 +445,7 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 40 / 100; let session_idx = 1; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); @@ -462,7 +462,7 @@ impl TestDisputes { let local_votes_count = self.validators_count * 90 / 100; let session_idx = 2; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Confirmed); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); @@ -478,7 +478,7 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 75 / 100; let session_idx = 3; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(0)); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); @@ -494,7 +494,7 @@ impl TestDisputes { let local_votes_count = self.validators_count * 90 / 100; let session_idx = 4; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::ConcludedFor(0)); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); @@ -510,7 +510,7 @@ impl TestDisputes { let onchain_votes_count = self.validators_count * 10 / 100; let session_idx = 5; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); @@ -527,7 +527,7 @@ impl TestDisputes { let local_votes_count = self.validators_count * 10 / 100; let session_idx = 6; let lf = leaf(); - let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt(lf.hash); + let dummy_receipt = polkadot_primitives_test_helpers::dummy_candidate_receipt_v2(lf.hash); for _ in 0..dispute_count { let d = (session_idx, CandidateHash(Hash::random()), DisputeStatus::Active); self.add_offchain_dispute(d, local_votes_count, dummy_receipt.clone()); diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index 9a06d9cff0cc..a95df6c5f880 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -41,9 +41,10 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - node_features::FeatureIndex, BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, - CoreIndex, CoreState, Hash, Id as ParaId, NodeFeatures, OccupiedCoreAssumption, SessionIndex, - SignedAvailabilityBitfield, ValidatorIndex, + node_features::FeatureIndex, + vstaging::{BackedCandidate, CandidateReceiptV2 as CandidateReceipt, CoreState}, + BlockNumber, CandidateHash, CoreIndex, Hash, Id as ParaId, NodeFeatures, + OccupiedCoreAssumption, SessionIndex, SignedAvailabilityBitfield, ValidatorIndex, }; use std::collections::{BTreeMap, HashMap}; @@ -361,10 +362,9 @@ fn note_provisionable_data( gum::trace!( target: LOG_TARGET, ?candidate_hash, - para = ?backed_candidate.descriptor().para_id, + para = ?backed_candidate.descriptor().para_id(), "noted backed candidate", ); - per_relay_parent.backed_candidates.push(backed_candidate); }, // We choose not to punish these forms of misbehavior for the time being. @@ -650,22 +650,22 @@ async fn select_candidate_hashes_from_tracked( // selection criteria if let Some(candidate) = candidates.iter().find(|backed_candidate| { let descriptor = &backed_candidate.descriptor; - descriptor.para_id == scheduled_core.para_id && - descriptor.persisted_validation_data_hash == computed_validation_data_hash + descriptor.para_id() == scheduled_core.para_id && + descriptor.persisted_validation_data_hash() == computed_validation_data_hash }) { let candidate_hash = candidate.hash(); gum::trace!( target: LOG_TARGET, leaf_hash=?relay_parent, ?candidate_hash, - para = ?candidate.descriptor.para_id, + para = ?candidate.descriptor.para_id(), core = core_idx, "Selected candidate receipt", ); selected_candidates.insert( - candidate.descriptor.para_id, - vec![(candidate_hash, candidate.descriptor.relay_parent)], + candidate.descriptor.para_id(), + vec![(candidate_hash, candidate.descriptor.relay_parent())], ); } } diff --git a/polkadot/node/core/provisioner/src/tests.rs b/polkadot/node/core/provisioner/src/tests.rs index b38459302c8f..a09b243f3ab1 100644 --- a/polkadot/node/core/provisioner/src/tests.rs +++ b/polkadot/node/core/provisioner/src/tests.rs @@ -16,14 +16,17 @@ use super::*; use bitvec::bitvec; -use polkadot_primitives::{OccupiedCore, ScheduledCore}; -use polkadot_primitives_test_helpers::{dummy_candidate_descriptor, dummy_hash}; +use polkadot_primitives::{ + vstaging::{MutateDescriptorV2, OccupiedCore}, + ScheduledCore, +}; +use polkadot_primitives_test_helpers::{dummy_candidate_descriptor_v2, dummy_hash}; const MOCK_GROUP_SIZE: usize = 5; pub fn occupied_core(para_id: u32) -> CoreState { - let mut candidate_descriptor = dummy_candidate_descriptor(dummy_hash()); - candidate_descriptor.para_id = para_id.into(); + let mut candidate_descriptor = dummy_candidate_descriptor_v2(dummy_hash()); + candidate_descriptor.set_para_id(para_id.into()); CoreState::Occupied(OccupiedCore { group_responsible: para_id.into(), @@ -32,7 +35,7 @@ pub fn occupied_core(para_id: u32) -> CoreState { time_out_at: 200_u32, next_up_on_time_out: None, availability: bitvec![u8, bitvec::order::Lsb0; 0; 32], - candidate_descriptor, + candidate_descriptor: candidate_descriptor.into(), candidate_hash: Default::default(), }) } @@ -254,9 +257,10 @@ mod select_candidates { use polkadot_node_subsystem_test_helpers::TestSubsystemSender; use polkadot_node_subsystem_util::runtime::ProspectiveParachainsMode; use polkadot_primitives::{ - BlockNumber, CandidateCommitments, CommittedCandidateReceipt, PersistedValidationData, + vstaging::{CommittedCandidateReceiptV2 as CommittedCandidateReceipt, MutateDescriptorV2}, + BlockNumber, CandidateCommitments, PersistedValidationData, }; - use polkadot_primitives_test_helpers::{dummy_candidate_descriptor, dummy_hash}; + use polkadot_primitives_test_helpers::{dummy_candidate_descriptor_v2, dummy_hash}; use rstest::rstest; use std::ops::Not; use CoreState::{Free, Scheduled}; @@ -266,8 +270,8 @@ mod select_candidates { fn dummy_candidate_template() -> CandidateReceipt { let empty_hash = PersistedValidationData::::default().hash(); - let mut descriptor_template = dummy_candidate_descriptor(dummy_hash()); - descriptor_template.persisted_validation_data_hash = empty_hash; + let mut descriptor_template = dummy_candidate_descriptor_v2(dummy_hash()); + descriptor_template.set_persisted_validation_data_hash(empty_hash); CandidateReceipt { descriptor: descriptor_template, commitments_hash: CandidateCommitments::default().hash(), @@ -283,7 +287,7 @@ mod select_candidates { .take(core_count) .enumerate() .map(|(idx, mut candidate)| { - candidate.descriptor.para_id = idx.into(); + candidate.descriptor.set_para_id(idx.into()); candidate }) .collect(); @@ -559,14 +563,14 @@ mod select_candidates { use RuntimeApiMessage::Request; let mut backed = expected.clone().into_iter().fold(HashMap::new(), |mut acc, candidate| { - acc.entry(candidate.descriptor().para_id).or_insert(vec![]).push(candidate); + acc.entry(candidate.descriptor().para_id()).or_insert(vec![]).push(candidate); acc }); - expected.sort_by_key(|c| c.candidate().descriptor.para_id); + expected.sort_by_key(|c| c.candidate().descriptor.para_id()); let mut candidates_iter = expected .iter() - .map(|candidate| (candidate.hash(), candidate.descriptor().relay_parent)); + .map(|candidate| (candidate.hash(), candidate.descriptor().relay_parent())); while let Some(from_job) = receiver.next().await { match from_job { @@ -601,7 +605,7 @@ mod select_candidates { candidates .iter() .map(|candidate| { - (candidate.hash(), candidate.descriptor().relay_parent) + (candidate.hash(), candidate.descriptor().relay_parent()) }) .collect(), ) @@ -707,7 +711,7 @@ mod select_candidates { .take(mock_cores.len()) .enumerate() .map(|(idx, mut candidate)| { - candidate.descriptor.para_id = idx.into(); + candidate.descriptor.set_para_id(idx.into()); candidate }) .cycle() @@ -719,11 +723,11 @@ mod select_candidates { candidate } else if idx < mock_cores.len() * 2 { // for the second repetition of the candidates, give them the wrong hash - candidate.descriptor.persisted_validation_data_hash = Default::default(); + candidate.descriptor.set_persisted_validation_data_hash(Default::default()); candidate } else { // third go-around: right hash, wrong para_id - candidate.descriptor.para_id = idx.into(); + candidate.descriptor.set_para_id(idx.into()); candidate } }) @@ -807,9 +811,9 @@ mod select_candidates { let committed_receipts: Vec<_> = (0..=mock_cores.len()) .map(|i| { - let mut descriptor = dummy_candidate_descriptor(dummy_hash()); - descriptor.para_id = i.into(); - descriptor.persisted_validation_data_hash = empty_hash; + let mut descriptor = dummy_candidate_descriptor_v2(dummy_hash()); + descriptor.set_para_id(i.into()); + descriptor.set_persisted_validation_data_hash(empty_hash); CommittedCandidateReceipt { descriptor, commitments: CandidateCommitments { @@ -917,14 +921,14 @@ mod select_candidates { let committed_receipts: Vec<_> = (0..mock_cores.len()) .map(|i| { - let mut descriptor = dummy_candidate_descriptor(dummy_hash()); - descriptor.para_id = if let Scheduled(scheduled_core) = &mock_cores[i] { + let mut descriptor = dummy_candidate_descriptor_v2(dummy_hash()); + descriptor.set_para_id(if let Scheduled(scheduled_core) = &mock_cores[i] { scheduled_core.para_id } else { panic!("`mock_cores` is not initialized with `Scheduled`?") - }; - descriptor.persisted_validation_data_hash = empty_hash; - descriptor.pov_hash = Hash::from_low_u64_be(i as u64); + }); + descriptor.set_persisted_validation_data_hash(empty_hash); + descriptor.set_pov_hash(Hash::from_low_u64_be(i as u64)); CommittedCandidateReceipt { descriptor, commitments: CandidateCommitments { @@ -1222,8 +1226,8 @@ mod select_candidates { .take(mock_cores.len() + 1) .enumerate() .map(|(idx, mut candidate)| { - candidate.descriptor.para_id = idx.into(); - candidate.descriptor.relay_parent = Hash::repeat_byte(idx as u8); + candidate.descriptor.set_para_id(idx.into()); + candidate.descriptor.set_relay_parent(Hash::repeat_byte(idx as u8)); candidate }) .collect(); diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index d603af04bf06..37d5878ea597 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -24,6 +24,7 @@ slotmap = { workspace = 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", @@ -37,6 +38,7 @@ polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-primitives = { 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 } @@ -51,6 +53,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/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 11031bf1074a..69355b8fd55d 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -35,15 +35,17 @@ use polkadot_node_core_pvf_common::{ SecurityStatus, }; use polkadot_node_primitives::PoV; -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::VecDeque, + collections::{HashMap, VecDeque}, fmt, path::PathBuf, sync::Arc, time::{Duration, Instant}, }; +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 @@ -56,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 }, } @@ -74,11 +77,13 @@ pub struct PendingExecutionRequest { pub pov: Arc, pub executor_params: ExecutorParams, pub result_tx: ResultSender, + pub exec_kind: PvfExecKind, } struct ExecuteJob { artifact: ArtifactPathId, exec_timeout: Duration, + exec_kind: PvfExecKind, pvd: Arc, pov: Arc, executor_params: ExecutorParams, @@ -140,7 +145,7 @@ impl Workers { enum QueueEvent { Spawn(IdleWorker, WorkerHandle, ExecuteJob), - StartWork( + FinishWork( Worker, Result, ArtifactId, @@ -166,9 +171,12 @@ struct Queue { security_status: SecurityStatus, /// The queue of jobs that are waiting for a worker to pick up. - queue: VecDeque, + unscheduled: Unscheduled, workers: Workers, mux: Mux, + + /// Active leaves and their ancestors to check the viability of backing jobs. + active_leaves: HashMap>, } impl Queue { @@ -192,13 +200,14 @@ impl Queue { security_status, to_queue_rx, from_queue_tx, - queue: VecDeque::new(), + unscheduled: Unscheduled::new(), mux: Mux::new(), workers: Workers { running: HopSlotMap::with_capacity_and_key(10), spawn_inflight: 0, capacity: worker_capacity, }, + active_leaves: Default::default(), } } @@ -226,9 +235,13 @@ impl Queue { /// If all the workers are busy or the queue is empty, it does nothing. /// Should be called every time a new job arrives to the queue or a job finishes. fn try_assign_next_job(&mut self, finished_worker: Option) { - // New jobs are always pushed to the tail of the queue; the one at its head is always - // the eldest one. - let eldest = if let Some(eldest) = self.queue.get(0) { eldest } else { return }; + // We always work at the same priority level + let priority = self.unscheduled.select_next_priority(); + let Some(queue) = self.unscheduled.get_mut(priority) else { return }; + + // New jobs are always pushed to the tail of the queue based on their priority; + // the one at its head of each queue is always the eldest one. + let eldest = if let Some(eldest) = queue.get(0) { eldest } else { return }; // By default, we're going to execute the eldest job on any worker slot available, even if // we have to kill and re-spawn a worker @@ -240,7 +253,7 @@ impl Queue { if eldest.waiting_since.elapsed() < MAX_KEEP_WAITING { if let Some(finished_worker) = finished_worker { if let Some(worker_data) = self.workers.running.get(finished_worker) { - for (i, job) in self.queue.iter().enumerate() { + for (i, job) in queue.iter().enumerate() { if worker_data.executor_params_hash == job.executor_params.hash() { (worker, job_index) = (Some(finished_worker), i); break @@ -252,7 +265,7 @@ impl Queue { if worker.is_none() { // Try to obtain a worker for the job - worker = self.workers.find_available(self.queue[job_index].executor_params.hash()); + worker = self.workers.find_available(queue[job_index].executor_params.hash()); } if worker.is_none() { @@ -270,13 +283,72 @@ impl Queue { return } - let job = self.queue.remove(job_index).expect("Job is just checked to be in queue; qed"); + 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(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", + ); + } + } } } @@ -296,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 } = - 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.queue.push_back(job); - 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) { @@ -324,7 +409,7 @@ async fn handle_mux(queue: &mut Queue, event: QueueEvent) { QueueEvent::Spawn(idle, handle, job) => { handle_worker_spawned(queue, idle, handle, job); }, - QueueEvent::StartWork(worker, outcome, artifact_id, result_tx) => { + QueueEvent::FinishWork(worker, outcome, artifact_id, result_tx) => { handle_job_finish(queue, worker, outcome, artifact_id, result_tx).await; }, } @@ -606,7 +691,7 @@ fn assign(queue: &mut Queue, worker: Worker, job: ExecuteJob) { job.pov, ) .await; - QueueEvent::StartWork(worker, result, job.artifact.id, job.result_tx) + QueueEvent::FinishWork(worker, result, job.artifact.id, job.result_tx) } .boxed(), ); @@ -638,3 +723,390 @@ pub fn start( .run(); (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, +} + +impl Unscheduled { + /// We keep track of every scheduled job in the `counter`, but reset it if the total number of + /// counted jobs reaches the threshold. This number is set as the maximum amount of jobs per + /// relay chain block possible with 4 CPU cores and 2 seconds of execution time. Under normal + /// conditions, the maximum expected queue size is at least vrf_module_samples(6) + 1 for + /// backing a parachain candidate. A buffer is added to cover situations where more work + /// arrives in the queue. + const SCHEDULING_WINDOW_SIZE: usize = 12; + + /// A threshold in percentages indicates how much time a current priority can "steal" from lower + /// priorities. Given the `SCHEDULING_WINDOW_SIZE` is 12 and all job priorities are present: + /// - Disputes consume 70% or 8 jobs in a row. + /// - The remaining 30% of original 100% is allocated for approval and all backing jobs. + /// - 80% or 3 jobs of the remaining goes to approvals. + /// - The remaining 6% of original 100% is allocated for all backing jobs. + /// - 100% or 1 job of the remaining goes to backing system parachains. + /// - Nothing is left for backing. + /// - The counter is restarted and the distribution starts from the beginning. + /// + /// This system might seem complex, but we operate with the remaining percentages because: + /// - Not all job types are present in each block. If we used parts of the original 100%, + /// 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 [(Priority, usize)] = &[ + (Priority::Dispute, 70), + (Priority::Approval, 80), + (Priority::BackingSystemParas, 100), + (Priority::Backing, 100), + ]; + + fn new() -> Self { + Self { + unscheduled: Priority::iter().map(|priority| (priority, VecDeque::new())).collect(), + counter: Priority::iter().map(|priority| (priority, 0)).collect(), + } + } + + fn select_next_priority(&self) -> Priority { + gum::debug!( + target: LOG_TARGET, + unscheduled = ?self.unscheduled.iter().map(|(p, q)| (*p, q.len())).collect::>(), + counter = ?self.counter, + "Selecting next execution priority...", + ); + + let priority = Priority::iter() + .find(|priority| self.has_pending(priority) && !self.has_reached_threshold(priority)) + .unwrap_or_else(|| { + Priority::iter() + .find(|priority| self.has_pending(priority)) + .unwrap_or(Priority::Backing) + }); + + gum::debug!( + target: LOG_TARGET, + ?priority, + "Selected next execution priority", + ); + + priority + } + + fn get_mut(&mut self, priority: Priority) -> Option<&mut VecDeque> { + self.unscheduled.get_mut(&priority) + } + + fn add(&mut self, job: ExecuteJob, priority: Priority) { + self.unscheduled.entry(priority).or_default().push_back(job); + } + + fn has_pending(&self, priority: &Priority) -> bool { + !self.unscheduled.get(priority).unwrap_or(&VecDeque::new()).is_empty() + } + + fn priority_allocation_threshold(priority: &Priority) -> Option { + Self::PRIORITY_ALLOCATION_THRESHOLDS.iter().find_map(|&(p, value)| { + if p == *priority { + Some(value) + } else { + None + } + }) + } + + /// Checks if a given priority has reached its allocated threshold + /// The thresholds are defined in `PRIORITY_ALLOCATION_THRESHOLDS`. + 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 + let total_scheduled_at_priority_or_lower: usize = self + .counter + .iter() + .filter_map(|(p, c)| if *p >= *priority { Some(c) } else { None }) + .sum(); + if total_scheduled_at_priority_or_lower == 0 { + return false + } + + let has_reached_threshold = count * 100 / total_scheduled_at_priority_or_lower >= threshold; + + gum::debug!( + target: LOG_TARGET, + ?priority, + ?count, + ?total_scheduled_at_priority_or_lower, + "Execution priority has {}reached threshold: {}/{}%", + if has_reached_threshold {""} else {"not "}, + count * 100 / total_scheduled_at_priority_or_lower, + threshold + ); + + has_reached_threshold + } + + 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 = 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::*; + use crate::testing::artifact_id; + use std::time::Duration; + + fn create_execution_job() -> ExecuteJob { + let (result_tx, _result_rx) = oneshot::channel(); + let pvd = Arc::new(PersistedValidationData { + parent_head: Default::default(), + relay_parent_number: 1u32, + relay_parent_storage_root: H256::default(), + max_pov_size: 4096 * 1024, + }); + let pov = Arc::new(PoV { block_data: BlockData(b"pov".to_vec()) }); + 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(), + result_tx, + waiting_since: Instant::now(), + } + } + + #[test] + fn test_unscheduled_add() { + let mut unscheduled = Unscheduled::new(); + + Priority::iter().for_each(|priority| { + unscheduled.add(create_execution_job(), priority); + }); + + Priority::iter().for_each(|priority| { + let queue = unscheduled.unscheduled.get(&priority).unwrap(); + assert_eq!(queue.len(), 1); + }); + } + + #[test] + fn test_unscheduled_priority_distribution() { + use Priority::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Dispute); + unscheduled.add(create_execution_job(), Approval); + unscheduled.add(create_execution_job(), BackingSystemParas); + unscheduled.add(create_execution_job(), Backing); + } + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Dispute).count(), 8); + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 3); + assert_eq!(priorities.iter().filter(|v| **v == BackingSystemParas).count(), 1); + } + + #[test] + fn test_unscheduled_priority_distribution_without_backing_system_paras() { + use Priority::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Dispute); + unscheduled.add(create_execution_job(), Approval); + unscheduled.add(create_execution_job(), Backing); + } + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Dispute).count(), 8); + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 3); + assert_eq!(priorities.iter().filter(|v| **v == Backing).count(), 1); + } + + #[test] + fn test_unscheduled_priority_distribution_without_disputes() { + use Priority::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Approval); + unscheduled.add(create_execution_job(), BackingSystemParas); + unscheduled.add(create_execution_job(), Backing); + } + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 9); + assert_eq!(priorities.iter().filter(|v| **v == BackingSystemParas).count(), 2); + assert_eq!(priorities.iter().filter(|v| **v == Backing).count(), 1); + } + + #[test] + fn test_unscheduled_priority_distribution_without_disputes_and_only_one_backing() { + use Priority::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Approval); + } + unscheduled.add(create_execution_job(), Backing); + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 11); + assert_eq!(priorities.iter().filter(|v| **v == Backing).count(), 1); + } + + #[test] + fn test_unscheduled_does_not_postpone_backing() { + use Priority::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Approval); + } + unscheduled.add(create_execution_job(), Backing); + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + 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 22943a06c43c..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::{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, @@ -114,6 +116,7 @@ impl ValidationHost { pvd: Arc, pov: Arc, priority: Priority, + exec_kind: PvfExecKind, result_tx: ResultSender, ) -> Result<(), String> { self.to_host_tx @@ -123,6 +126,7 @@ impl ValidationHost { pvd, pov, priority, + exec_kind, result_tx, })) .await @@ -141,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 { @@ -155,6 +174,7 @@ struct ExecutePvfInputs { pvd: Arc, pov: Arc, priority: Priority, + exec_kind: PvfExecKind, result_tx: ResultSender, } @@ -485,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(()) @@ -545,7 +567,7 @@ async fn handle_execute_pvf( awaiting_prepare: &mut AwaitingPrepare, inputs: ExecutePvfInputs, ) -> Result<(), Fatal> { - let ExecutePvfInputs { pvf, exec_timeout, pvd, pov, priority, result_tx } = inputs; + let ExecutePvfInputs { pvf, exec_timeout, pvd, pov, priority, exec_kind, result_tx } = inputs; let artifact_id = ArtifactId::from_pvf_prep_data(&pvf); let executor_params = (*pvf.executor_params()).clone(); @@ -567,6 +589,7 @@ async fn handle_execute_pvf( pvd, pov, executor_params, + exec_kind, result_tx, }, }, @@ -597,6 +620,7 @@ async fn handle_execute_pvf( pvd, pov, executor_params, + exec_kind, result_tx, }, ) @@ -606,7 +630,14 @@ async fn handle_execute_pvf( ArtifactState::Preparing { .. } => { awaiting_prepare.add( artifact_id, - PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx }, + PendingExecutionRequest { + exec_timeout, + pvd, + pov, + executor_params, + result_tx, + exec_kind, + }, ); }, ArtifactState::FailedToProcess { last_time_failed, num_failures, error } => { @@ -638,6 +669,7 @@ async fn handle_execute_pvf( pvd, pov, executor_params, + exec_kind, result_tx, }, ) @@ -657,7 +689,14 @@ async fn handle_execute_pvf( pvf, priority, artifact_id, - PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx }, + PendingExecutionRequest { + exec_timeout, + pvd, + pov, + executor_params, + result_tx, + exec_kind, + }, ) .await?; } @@ -779,7 +818,7 @@ async fn handle_prepare_done( // It's finally time to dispatch all the execution requests that were waiting for this artifact // to be prepared. let pending_requests = awaiting_prepare.take(&artifact_id); - for PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx } in + for PendingExecutionRequest { exec_timeout, pvd, pov, executor_params, result_tx, exec_kind } in pending_requests { if result_tx.is_canceled() { @@ -805,6 +844,7 @@ async fn handle_prepare_done( pvd, pov, executor_params, + exec_kind, result_tx, }, }, @@ -834,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, @@ -1234,6 +1282,7 @@ pub(crate) mod tests { pvd.clone(), pov1.clone(), Priority::Normal, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1246,6 +1295,7 @@ pub(crate) mod tests { pvd.clone(), pov1, Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1258,6 +1308,7 @@ pub(crate) mod tests { pvd, pov2, Priority::Normal, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1407,6 +1458,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1455,6 +1507,7 @@ pub(crate) mod tests { pvd, pov, Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1565,6 +1618,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1596,6 +1650,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx_2, ) .await @@ -1619,6 +1674,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx_3, ) .await @@ -1677,6 +1733,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx, ) .await @@ -1708,6 +1765,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx_2, ) .await @@ -1731,6 +1789,7 @@ pub(crate) mod tests { pvd.clone(), pov.clone(), Priority::Critical, + PvfExecKind::Backing(H256::default()), result_tx_3, ) .await @@ -1805,6 +1864,7 @@ pub(crate) mod tests { pvd, pov, Priority::Normal, + PvfExecKind::Backing(H256::default()), result_tx, ) .await diff --git a/polkadot/node/core/pvf/src/metrics.rs b/polkadot/node/core/pvf/src/metrics.rs index c59cab464180..745f2de99e58 100644 --- a/polkadot/node/core/pvf/src/metrics.rs +++ b/polkadot/node/core/pvf/src/metrics.rs @@ -18,6 +18,7 @@ use polkadot_node_core_pvf_common::prepare::MemoryStats; use polkadot_node_metrics::metrics::{self, prometheus}; +use polkadot_node_subsystem::messages::PvfExecKind; /// Validation host metrics. #[derive(Default, Clone)] @@ -120,6 +121,13 @@ impl Metrics { .observe(pov_size as f64); } } + + /// When preparation pipeline concluded working on an item. + pub(crate) fn on_execute_kind(&self, kind: PvfExecKind) { + if let Some(metrics) = &self.0 { + metrics.exec_kind_selected.with_label_values(&[kind.as_str()]).inc(); + } + } } #[derive(Clone)] @@ -146,6 +154,7 @@ struct MetricsInner { preparation_peak_tracked_allocation: prometheus::Histogram, pov_size: prometheus::HistogramVec, code_size: prometheus::Histogram, + exec_kind_selected: prometheus::CounterVec, } impl metrics::Metrics for Metrics { @@ -369,6 +378,16 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + exec_kind_selected: prometheus::register( + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_pvf_exec_kind_selected", + "The total number of selected execute kinds", + ), + &["priority"], + )?, + registry, + )?, }; Ok(Metrics(Some(inner))) } diff --git a/polkadot/node/core/pvf/src/priority.rs b/polkadot/node/core/pvf/src/priority.rs index 0d18d4b484ca..5a58fbc8ade3 100644 --- a/polkadot/node/core/pvf/src/priority.rs +++ b/polkadot/node/core/pvf/src/priority.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use polkadot_node_subsystem::messages::PvfExecKind; + /// A priority assigned to preparation of a PVF. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Priority { @@ -35,3 +37,14 @@ impl Priority { self == Priority::Critical } } + +impl From for Priority { + fn from(priority: PvfExecKind) -> Self { + match priority { + PvfExecKind::Dispute => Priority::Critical, + PvfExecKind::Approval => Priority::Critical, + 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 a4a085318957..cfb78fd530d2 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -25,9 +25,11 @@ use polkadot_node_core_pvf::{ ValidationHost, JOB_TIMEOUT_WALL_CLOCK_FACTOR, }; 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, PvfPrepKind, + ExecutorParam, ExecutorParams, Hash, PersistedValidationData, + PvfExecKind as RuntimePvfExecKind, PvfPrepKind, }; use sp_core::H256; @@ -106,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(); @@ -123,6 +126,7 @@ impl TestHost { Arc::new(pvd), Arc::new(pov), polkadot_node_core_pvf::Priority::Normal, + PvfExecKind::Backing(relay_parent), result_tx, ) .await @@ -168,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 { @@ -198,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(); @@ -251,6 +263,7 @@ async fn execute_queue_doesnt_stall_if_workers_died() { pvd.clone(), pov.clone(), Default::default(), + H256::default(), ) })) .await; @@ -300,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; @@ -356,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))); @@ -407,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!( @@ -580,8 +606,9 @@ async fn artifact_does_not_reprepare_on_non_meaningful_exec_parameter_change() { let cache_dir = host.cache_dir.path(); let set1 = ExecutorParams::default(); - let set2 = - ExecutorParams::from(&[ExecutorParam::PvfExecTimeout(PvfExecKind::Backing, 2500)][..]); + let set2 = ExecutorParams::from( + &[ExecutorParam::PvfExecTimeout(RuntimePvfExecKind::Backing, 2500)][..], + ); let _stats = host .precheck_pvf(test_parachain_halt::wasm_binary_unwrap(), set1) @@ -680,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, @@ -704,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/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 05efbc533d02..7246010711e4 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -20,12 +20,16 @@ use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ - async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, - CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, + async_backing, slashing, vstaging, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateHash, + CoreIndex, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, - PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, + PersistedValidationData, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -66,7 +70,7 @@ pub(crate) struct RequestResultCache { key_ownership_proof: LruMap<(Hash, ValidatorId), Option>, minimum_backing_votes: LruMap, disabled_validators: LruMap>, - para_backing_state: LruMap<(Hash, ParaId), Option>, + para_backing_state: LruMap<(Hash, ParaId), Option>, async_backing_params: LruMap, node_features: LruMap, approval_voting_params: LruMap, @@ -499,14 +503,14 @@ impl RequestResultCache { pub(crate) fn para_backing_state( &mut self, key: (Hash, ParaId), - ) -> Option<&Option> { + ) -> Option<&Option> { self.para_backing_state.get(&key).map(|v| &*v) } pub(crate) fn cache_para_backing_state( &mut self, key: (Hash, ParaId), - value: Option, + value: Option, ) { self.para_backing_state.insert(key, value); } @@ -601,7 +605,7 @@ pub(crate) enum RequestResult { SubmitReportDisputeLost(Option<()>), ApprovalVotingParams(Hash, SessionIndex, ApprovalVotingParams), DisabledValidators(Hash, Vec), - ParaBackingState(Hash, ParaId, Option), + ParaBackingState(Hash, ParaId, Option), AsyncBackingParams(Hash, async_backing::AsyncBackingParams), NodeFeatures(SessionIndex, NodeFeatures), ClaimQueue(Hash, BTreeMap>), diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index 7c382707264f..d4fa07323886 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -20,14 +20,20 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_primitives::{ - async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, - CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Id as ParaId, + async_backing, slashing, vstaging, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateHash, + CoreIndex, DisputeState, ExecutorParams, GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - Slot, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + PersistedValidationData, PvfCheckStatement, SessionIndex, SessionInfo, Slot, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, +}; +use polkadot_primitives_test_helpers::{ + dummy_committed_candidate_receipt_v2, dummy_validation_code, }; -use polkadot_primitives_test_helpers::{dummy_committed_candidate_receipt, dummy_validation_code}; use sp_api::ApiError; use sp_core::testing::TaskExecutor; use std::{ @@ -279,7 +285,7 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { &self, _: Hash, _: ParaId, - ) -> Result, ApiError> { + ) -> Result, ApiError> { todo!("Not required for tests") } @@ -699,7 +705,7 @@ fn requests_candidate_pending_availability() { let para_a = ParaId::from(5_u32); let para_b = ParaId::from(6_u32); let spawner = sp_core::testing::TaskExecutor::new(); - let candidate_receipt = dummy_committed_candidate_receipt(relay_parent); + let candidate_receipt = dummy_committed_candidate_receipt_v2(relay_parent); let mut subsystem_client = MockSubsystemClient::default(); subsystem_client diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index 50a5af63db44..7415e6c79df5 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -24,8 +24,10 @@ use crate::{ use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; use polkadot_primitives::{ - CandidateCommitments, CandidateDescriptor, CandidateReceipt, PersistedValidationData, - PvfExecKind, + vstaging::{ + CandidateDescriptorV2 as CandidateDescriptor, CandidateReceiptV2 as CandidateReceipt, + }, + CandidateCommitments, PersistedValidationData, PvfExecKind, }; use futures::channel::oneshot; @@ -203,7 +205,7 @@ fn create_validation_response( gum::debug!( target: MALUS, - para_id = ?candidate_receipt.descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id(), candidate_hash = ?candidate_receipt.hash(), "ValidationResult: {:?}", &result @@ -241,7 +243,7 @@ where }, } => { match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(exec_kind) => { + x if x.misbehaves_valid() && x.should_misbehave(exec_kind.into()) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { @@ -296,7 +298,7 @@ where }, } }, - x if x.misbehaves_invalid() && x.should_misbehave(exec_kind) => { + x if x.misbehaves_invalid() && x.should_misbehave(exec_kind.into()) => { // Set the validation result to invalid with probability `p` and trigger a // dispute let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); @@ -308,7 +310,7 @@ where gum::info!( target: MALUS, ?behave_maliciously, - para_id = ?candidate_receipt.descriptor.para_id, + para_id = ?candidate_receipt.descriptor.para_id(), "😈 Maliciously sending invalid validation result: {:?}.", &validation_result, ); diff --git a/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs b/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs index 7a95bdaead26..309be9e46d82 100644 --- a/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs +++ b/polkadot/node/malus/src/variants/dispute_finalized_candidates.rs @@ -42,7 +42,7 @@ use polkadot_cli::{ use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_types::{ChainApiBackend, OverseerSignal, RuntimeApiSubsystemClient}; use polkadot_node_subsystem_util::request_candidate_events; -use polkadot_primitives::CandidateEvent; +use polkadot_primitives::vstaging::CandidateEvent; use sp_core::traits::SpawnNamed; // Filter wrapping related types. diff --git a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs index ab2d380fbaf4..2fe08c8a1c49 100644 --- a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs @@ -32,7 +32,7 @@ use polkadot_cli::{ }; use polkadot_node_primitives::{AvailableData, BlockData, PoV}; use polkadot_node_subsystem_types::{ChainApiBackend, RuntimeApiSubsystemClient}; -use polkadot_primitives::{CandidateDescriptor, CandidateReceipt}; +use polkadot_primitives::{vstaging::CandidateReceiptV2, CandidateDescriptor}; use polkadot_node_subsystem_util::request_validators; use sp_core::traits::SpawnNamed; @@ -127,7 +127,7 @@ where let validation_code = { let validation_code_hash = - _candidate.descriptor().validation_code_hash; + _candidate.descriptor().validation_code_hash(); let (tx, rx) = oneshot::channel(); new_sender .send_message(RuntimeApiMessage::Request( @@ -214,7 +214,7 @@ where let collator_pair = CollatorPair::generate().0; let signature_payload = polkadot_primitives::collator_signature_payload( &relay_parent, - &candidate.descriptor().para_id, + &candidate.descriptor().para_id(), &validation_data_hash, &pov_hash, &validation_code_hash, @@ -227,9 +227,9 @@ where &malicious_available_data.validation_data, ); - let malicious_candidate = CandidateReceipt { + let malicious_candidate = CandidateReceiptV2 { descriptor: CandidateDescriptor { - para_id: candidate.descriptor().para_id, + para_id: candidate.descriptor.para_id(), relay_parent, collator: collator_id, persisted_validation_data_hash: validation_data_hash, @@ -238,7 +238,8 @@ where signature: collator_signature, para_head: malicious_commitments.head_data.hash(), validation_code_hash, - }, + } + .into(), commitments_hash: malicious_commitments.hash(), }; let malicious_candidate_hash = malicious_candidate.hash(); diff --git a/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs b/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs index 5be6f2d223a8..c4654b843c44 100644 --- a/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs @@ -35,8 +35,8 @@ use polkadot_node_subsystem::{ overseer, }; use polkadot_primitives::{ - AuthorityDiscoveryId, BlakeTwo256, CandidateHash, ChunkIndex, GroupIndex, Hash, HashT, - OccupiedCore, SessionIndex, + vstaging::OccupiedCore, AuthorityDiscoveryId, BlakeTwo256, CandidateHash, ChunkIndex, + GroupIndex, Hash, HashT, SessionIndex, }; use sc_network::ProtocolName; @@ -170,8 +170,8 @@ impl FetchTaskConfig { candidate_hash: core.candidate_hash, index: session_info.our_index, }, - erasure_root: core.candidate_descriptor.erasure_root, - relay_parent: core.candidate_descriptor.relay_parent, + erasure_root: core.candidate_descriptor.erasure_root(), + relay_parent: core.candidate_descriptor.relay_parent(), metrics, sender, chunk_index, diff --git a/polkadot/node/network/availability-distribution/src/requester/mod.rs b/polkadot/node/network/availability-distribution/src/requester/mod.rs index 233825032724..613a514269ee 100644 --- a/polkadot/node/network/availability-distribution/src/requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/mod.rs @@ -38,7 +38,7 @@ use polkadot_node_subsystem_util::{ availability_chunks::availability_chunk_index, runtime::{get_occupied_cores, RuntimeInfo}, }; -use polkadot_primitives::{CandidateHash, CoreIndex, Hash, OccupiedCore, SessionIndex}; +use polkadot_primitives::{vstaging::OccupiedCore, CandidateHash, CoreIndex, Hash, SessionIndex}; use super::{FatalError, Metrics, Result, LOG_TARGET}; diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index 021f6da7e2e9..ebcba2a038bc 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -21,7 +21,7 @@ use polkadot_node_network_protocol::request_response::ReqProtocolNames; use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - BlockNumber, ChunkIndex, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, + vstaging::CoreState, BlockNumber, ChunkIndex, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, SessionIndex, SessionInfo, }; use sp_core::{testing::TaskExecutor, traits::SpawnNamed}; diff --git a/polkadot/node/network/availability-distribution/src/tests/mock.rs b/polkadot/node/network/availability-distribution/src/tests/mock.rs index b41c493a1072..f900cb6e6156 100644 --- a/polkadot/node/network/availability-distribution/src/tests/mock.rs +++ b/polkadot/node/network/availability-distribution/src/tests/mock.rs @@ -23,8 +23,9 @@ use sp_keyring::Sr25519Keyring; use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks}; use polkadot_node_primitives::{AvailableData, BlockData, ErasureChunk, PoV, Proof}; use polkadot_primitives::{ + vstaging::{CommittedCandidateReceiptV2, OccupiedCore}, CandidateCommitments, CandidateDescriptor, CandidateHash, ChunkIndex, - CommittedCandidateReceipt, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, OccupiedCore, + CommittedCandidateReceipt, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, PersistedValidationData, SessionInfo, ValidatorIndex, }; use polkadot_primitives_test_helpers::{ @@ -101,7 +102,7 @@ impl OccupiedCoreBuilder { availability: Default::default(), group_responsible: self.group_responsible, candidate_hash: candidate_receipt.hash(), - candidate_descriptor: candidate_receipt.descriptor().clone(), + candidate_descriptor: candidate_receipt.descriptor.clone(), }; (core, (candidate_receipt.hash(), chunk)) } @@ -117,7 +118,7 @@ pub struct TestCandidateBuilder { } impl TestCandidateBuilder { - pub fn build(self) -> CommittedCandidateReceipt { + pub fn build(self) -> CommittedCandidateReceiptV2 { CommittedCandidateReceipt { descriptor: CandidateDescriptor { para_id: self.para_id, @@ -132,6 +133,7 @@ impl TestCandidateBuilder { }, commitments: CandidateCommitments { head_data: self.head_data, ..Default::default() }, } + .into() } } diff --git a/polkadot/node/network/availability-distribution/src/tests/mod.rs b/polkadot/node/network/availability-distribution/src/tests/mod.rs index 078220607c37..d4abd4e32d9b 100644 --- a/polkadot/node/network/availability-distribution/src/tests/mod.rs +++ b/polkadot/node/network/availability-distribution/src/tests/mod.rs @@ -22,7 +22,7 @@ use rstest::rstest; use polkadot_node_network_protocol::request_response::{ IncomingRequest, Protocol, ReqProtocolNames, }; -use polkadot_primitives::{node_features, Block, CoreState, Hash, NodeFeatures}; +use polkadot_primitives::{node_features, vstaging::CoreState, Block, Hash, NodeFeatures}; use sp_keystore::KeystorePtr; use super::*; diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 53d6fd2c530f..c6dd17a344e0 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -47,7 +47,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - CandidateHash, ChunkIndex, CoreIndex, CoreState, ExecutorParams, GroupIndex, Hash, + vstaging::CoreState, CandidateHash, ChunkIndex, CoreIndex, ExecutorParams, GroupIndex, Hash, Id as ParaId, NodeFeatures, ScheduledCore, SessionInfo, ValidatorIndex, }; use test_helpers::mock::{make_ferdie_keystore, new_leaf}; diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index 114faa2859c4..eb54d9657d83 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -66,8 +66,8 @@ use polkadot_node_subsystem_util::{ runtime::{ExtendedSessionInfo, RuntimeInfo}, }; use polkadot_primitives::{ - node_features, BlockNumber, CandidateHash, CandidateReceipt, ChunkIndex, CoreIndex, GroupIndex, - Hash, SessionIndex, ValidatorIndex, + node_features, vstaging::CandidateReceiptV2 as CandidateReceipt, BlockNumber, CandidateHash, + ChunkIndex, CoreIndex, GroupIndex, Hash, SessionIndex, ValidatorIndex, }; mod error; @@ -540,11 +540,11 @@ async fn handle_recover( threshold: recovery_threshold(n_validators)?, systematic_threshold, candidate_hash, - erasure_root: receipt.descriptor.erasure_root, + erasure_root: receipt.descriptor.erasure_root(), metrics: metrics.clone(), bypass_availability_store, post_recovery_check, - pov_hash: receipt.descriptor.pov_hash, + pov_hash: receipt.descriptor.pov_hash(), req_v1_protocol_name, req_v2_protocol_name, chunk_mapping_enabled, diff --git a/polkadot/node/network/availability-recovery/src/tests.rs b/polkadot/node/network/availability-recovery/src/tests.rs index 4fd9ede40ff6..9a46d5420782 100644 --- a/polkadot/node/network/availability-recovery/src/tests.rs +++ b/polkadot/node/network/availability-recovery/src/tests.rs @@ -41,8 +41,8 @@ use polkadot_node_subsystem_test_helpers::{ }; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ - node_features, AuthorityDiscoveryId, Block, ExecutorParams, Hash, HeadData, IndexedVec, - NodeFeatures, PersistedValidationData, SessionInfo, ValidatorId, + node_features, vstaging::MutateDescriptorV2, AuthorityDiscoveryId, Block, ExecutorParams, Hash, + HeadData, IndexedVec, NodeFeatures, PersistedValidationData, SessionInfo, ValidatorId, }; use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; use sc_network::{IfDisconnected, OutboundFailure, ProtocolName, RequestFailure}; @@ -346,7 +346,7 @@ impl TestState { ) .unwrap(), current, - candidate, + candidate: candidate.into(), session_index, core_index, node_features, @@ -800,12 +800,12 @@ fn availability_is_recovered_from_chunks_if_no_group_provided(#[case] systematic // Test another candidate, send no chunks. let mut new_candidate = dummy_candidate_receipt(dummy_hash()); - new_candidate.descriptor.relay_parent = test_state.candidate.descriptor.relay_parent; + new_candidate.descriptor.relay_parent = test_state.candidate.descriptor.relay_parent(); overseer_send( &mut virtual_overseer, AvailabilityRecoveryMessage::RecoverAvailableData( - new_candidate.clone(), + new_candidate.clone().into(), test_state.session_index, None, Some(test_state.core_index), @@ -929,12 +929,12 @@ fn availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunk // Test another candidate, send no chunks. let mut new_candidate = dummy_candidate_receipt(dummy_hash()); - new_candidate.descriptor.relay_parent = test_state.candidate.descriptor.relay_parent; + new_candidate.descriptor.relay_parent = test_state.candidate.descriptor.relay_parent(); overseer_send( &mut virtual_overseer, AvailabilityRecoveryMessage::RecoverAvailableData( - new_candidate.clone(), + new_candidate.clone().into(), test_state.session_index, Some(GroupIndex(1)), Some(test_state.core_index), @@ -1218,7 +1218,7 @@ fn invalid_erasure_coding_leads_to_invalid_error(#[case] systematic_recovery: bo test_state.validators.len(), test_state.core_index, ); - test_state.candidate.descriptor.erasure_root = bad_erasure_root; + test_state.candidate.descriptor.set_erasure_root(bad_erasure_root); let candidate_hash = test_state.candidate.hash(); @@ -1283,7 +1283,7 @@ fn invalid_pov_hash_leads_to_invalid_error() { test_harness(subsystem, |mut virtual_overseer| async move { let pov = PoV { block_data: BlockData(vec![69; 64]) }; - test_state.candidate.descriptor.pov_hash = pov.hash(); + test_state.candidate.descriptor.set_pov_hash(pov.hash()); let candidate_hash = test_state.candidate.hash(); @@ -1420,7 +1420,10 @@ fn recovers_from_only_chunks_if_pov_large( test_state.threshold(), ), (false, true) => { - test_state.candidate.descriptor.pov_hash = test_state.available_data.pov.hash(); + test_state + .candidate + .descriptor + .set_pov_hash(test_state.available_data.pov.hash()); ( AvailabilityRecoverySubsystem::for_collator( None, @@ -1497,12 +1500,12 @@ fn recovers_from_only_chunks_if_pov_large( // Test another candidate, send no chunks. let mut new_candidate = dummy_candidate_receipt(dummy_hash()); - new_candidate.descriptor.relay_parent = test_state.candidate.descriptor.relay_parent; + new_candidate.descriptor.relay_parent = test_state.candidate.descriptor.relay_parent(); overseer_send( &mut virtual_overseer, AvailabilityRecoveryMessage::RecoverAvailableData( - new_candidate.clone(), + new_candidate.clone().into(), test_state.session_index, Some(GroupIndex(1)), Some(test_state.core_index), @@ -1593,7 +1596,10 @@ fn fast_path_backing_group_recovers_if_pov_small( Metrics::new_dummy(), ), (false, true) => { - test_state.candidate.descriptor.pov_hash = test_state.available_data.pov.hash(); + test_state + .candidate + .descriptor + .set_pov_hash(test_state.available_data.pov.hash()); AvailabilityRecoverySubsystem::for_collator( None, request_receiver(&req_protocol_names), @@ -2635,7 +2641,7 @@ fn number_of_request_retries_is_bounded( ); test_state.chunks = map_chunks(chunks, &test_state.node_features, n_validators, test_state.core_index); - test_state.candidate.descriptor.erasure_root = erasure_root; + test_state.candidate.descriptor.set_erasure_root(erasure_root); let (subsystem, retry_limit) = match systematic_recovery { false => ( diff --git a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs index 57e1479a449b..6a570331f710 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/collation.rs @@ -28,7 +28,9 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::PoV; use polkadot_node_subsystem::messages::ParentHeadData; -use polkadot_primitives::{CandidateHash, CandidateReceipt, Hash, Id as ParaId}; +use polkadot_primitives::{ + vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, Hash, Id as ParaId, +}; /// The status of a collation as seen from the collator. pub enum CollationStatus { 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 af9beb535f46..504b0d716043 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -54,8 +54,9 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateHash, CandidateReceipt, CollatorPair, CoreIndex, CoreState, - GroupIndex, Hash, HeadData, Id as ParaId, SessionIndex, + vstaging::{CandidateReceiptV2 as CandidateReceipt, CoreState}, + AuthorityDiscoveryId, CandidateHash, CollatorPair, CoreIndex, GroupIndex, Hash, HeadData, + Id as ParaId, SessionIndex, }; use super::LOG_TARGET; @@ -374,7 +375,7 @@ async fn distribute_collation( result_sender: Option>, core_index: CoreIndex, ) -> Result<()> { - let candidate_relay_parent = receipt.descriptor.relay_parent; + let candidate_relay_parent = receipt.descriptor.relay_parent(); let candidate_hash = receipt.hash(); let per_relay_parent = match state.per_relay_parent.get_mut(&candidate_relay_parent) { @@ -850,12 +851,12 @@ async fn process_msg( core_index, } => { match state.collating_on { - Some(id) if candidate_receipt.descriptor.para_id != id => { + Some(id) if candidate_receipt.descriptor.para_id() != id => { // If the ParaId of a collation requested to be distributed does not match // the one we expect, we ignore the message. gum::warn!( target: LOG_TARGET, - para_id = %candidate_receipt.descriptor.para_id, + para_id = %candidate_receipt.descriptor.para_id(), collating_on = %id, "DistributeCollation for unexpected para_id", ); @@ -879,7 +880,7 @@ async fn process_msg( None => { gum::warn!( target: LOG_TARGET, - para_id = %candidate_receipt.descriptor.para_id, + para_id = %candidate_receipt.descriptor.para_id(), "DistributeCollation message while not collating on any", ); }, diff --git a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs index fbb3ff4328a5..35202fc96299 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/validators_buffer.rs @@ -110,7 +110,7 @@ impl ValidatorGroupsBuffer { .validators .iter() .enumerate() - .filter_map(|(idx, authority_id)| bits[idx].then_some(authority_id.clone())) + .filter_map(|(idx, authority_id)| bits[idx].then(|| authority_id.clone())) .collect(); if let Some(last_group) = self.group_infos.iter().last() { diff --git a/polkadot/node/network/collator-protocol/src/error.rs b/polkadot/node/network/collator-protocol/src/error.rs index 0f5e0699d85c..ae7f9a8c1fbc 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,12 @@ 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), } /// An error happened on the validator side of the protocol when attempting @@ -87,11 +94,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 +121,11 @@ impl SecondingError { self, PersistedValidationDataMismatch | CandidateHashMismatch | - Duplicate | ParentHeadDataMismatch + RelayParentMismatch | + Duplicate | ParentHeadDataMismatch | + InvalidCoreIndex(_, _) | + InvalidSessionIndex(_, _) | + InvalidReceiptVersion(_) ) } } 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 58d9ebc57726..cc0de1cb70f6 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -40,8 +40,8 @@ use polkadot_node_subsystem_util::{ metrics::prometheus::prometheus::HistogramTimer, runtime::ProspectiveParachainsMode, }; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CollatorId, Hash, HeadData, Id as ParaId, - PersistedValidationData, + vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, CollatorId, Hash, HeadData, + Id as ParaId, PersistedValidationData, }; use tokio_util::sync::CancellationToken; @@ -71,18 +71,15 @@ pub struct FetchedCollation { pub para_id: ParaId, /// Candidate hash. pub candidate_hash: CandidateHash, - /// Id of the collator the collation was fetched from. - pub collator_id: CollatorId, } impl From<&CandidateReceipt> for FetchedCollation { fn from(receipt: &CandidateReceipt) -> Self { let descriptor = receipt.descriptor(); Self { - relay_parent: descriptor.relay_parent, - para_id: descriptor.para_id, + relay_parent: descriptor.relay_parent(), + para_id: descriptor.para_id(), candidate_hash: receipt.hash(), - collator_id: descriptor.collator.clone(), } } } @@ -132,27 +129,32 @@ 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, persisted_validation_data: &PersistedValidationData, 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 + if persisted_validation_data.hash() != fetched.descriptor().persisted_validation_data_hash() { + 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. 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 deb6ce03f43e..86358f503d04 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -49,11 +49,14 @@ 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_claim_queue, request_session_index_for_child, + runtime::{prospective_parachains_mode, request_node_features, ProspectiveParachainsMode}, }; use polkadot_primitives::{ - CandidateHash, CollatorId, CoreState, Hash, HeadData, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, + node_features, + vstaging::{CandidateDescriptorV2, CandidateDescriptorVersion, CoreState}, + CandidateHash, CollatorId, CoreIndex, Hash, HeadData, Id as ParaId, OccupiedCoreAssumption, + PersistedValidationData, SessionIndex, }; use crate::error::{Error, FetchError, Result, SecondingError}; @@ -369,16 +372,9 @@ 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. @@ -460,14 +456,15 @@ fn is_relay_parent_in_implicit_view( } } -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, { @@ -494,25 +491,25 @@ where rotation_info.core_for_group(group, cores.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 claim_queue = request_claim_queue(relay_parent, sender) + .await + .await + .map_err(Error::CancelledClaimQueue)??; + + let paras_now = cores + .get(core_now.0 as usize) + .and_then(|c| match (c, relay_parent_mode) { + (CoreState::Occupied(_), ProspectiveParachainsMode::Disabled) => None, + ( + CoreState::Occupied(_), + ProspectiveParachainsMode::Enabled { max_candidate_depth: 0, .. }, + ) => None, + _ => claim_queue.get(&core_now).cloned(), + }) + .unwrap_or_else(|| VecDeque::new()); for para_id in paras_now.iter() { let entry = current_assignments.entry(*para_id).or_default(); @@ -527,9 +524,14 @@ where } } - *group_assignment = GroupAssignments { current: paras_now.into_iter().collect() }; - - Ok(()) + Ok(Some(PerRelayParent { + prospective_parachains_mode: relay_parent_mode, + assignment: GroupAssignments { current: paras_now.into_iter().collect() }, + collations: Collations::default(), + v2_receipts, + session_index, + current_core: core_now, + })) } fn remove_outgoing( @@ -1021,7 +1023,7 @@ async fn second_unblocked_collations( for mut unblocked_collation in unblocked_collations { unblocked_collation.maybe_parent_head_data = Some(head_data.clone()); let peer_id = unblocked_collation.collation_event.pending_collation.peer_id; - let relay_parent = unblocked_collation.candidate_receipt.descriptor.relay_parent; + let relay_parent = unblocked_collation.candidate_receipt.descriptor.relay_parent(); if let Err(err) = kick_off_seconding(ctx, state, unblocked_collation).await { gum::warn!( @@ -1249,18 +1251,31 @@ where let added = view.iter().filter(|h| !current_leaves.contains_key(h)); for leaf in added { + let session_index = request_session_index_for_child(*leaf, sender) + .await + .await + .map_err(Error::CancelledSessionIndex)??; let mode = prospective_parachains_mode(sender, *leaf).await?; - - let mut per_relay_parent = PerRelayParent::new(mode); - assign_incoming( + 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.per_relay_parent.insert(*leaf, per_relay_parent); @@ -1279,18 +1294,21 @@ where .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( + // 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 per_relay_parent.assignment, &mut state.current_assignments, keystore, *block_hash, mode, + v2_receipts, + session_index, ) - .await?; - - entry.insert(per_relay_parent); + .await? + { + entry.insert(per_relay_parent); + } } } } @@ -1328,7 +1346,7 @@ where collations.retain(|collation| { state .per_relay_parent - .contains_key(&collation.candidate_receipt.descriptor.relay_parent) + .contains_key(&collation.candidate_receipt.descriptor.relay_parent()) }); !collations.is_empty() @@ -1470,7 +1488,7 @@ async fn process_msg( }, }; let output_head_data = receipt.commitments.head_data.clone(); - let output_head_data_hash = receipt.descriptor.para_head; + let output_head_data_hash = receipt.descriptor.para_head(); let fetched_collation = FetchedCollation::from(&receipt.to_plain()); if let Some(CollationEvent { collator_id, pending_collation, .. }) = state.fetched_candidates.remove(&fetched_collation) @@ -1531,8 +1549,8 @@ async fn process_msg( Invalid(parent, candidate_receipt) => { // Remove collations which were blocked from seconding and had this candidate as parent. state.blocked_from_seconding.remove(&BlockedCollationId { - para_id: candidate_receipt.descriptor.para_id, - parent_head_data_hash: candidate_receipt.descriptor.para_head, + para_id: candidate_receipt.descriptor.para_id(), + parent_head_data_hash: candidate_receipt.descriptor.para_head(), }); let fetched_collation = FetchedCollation::from(&candidate_receipt); @@ -1621,11 +1639,10 @@ 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 res = match handle_collation_fetch_response( &mut state, @@ -1684,7 +1701,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!( @@ -1814,6 +1831,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); @@ -1843,8 +1864,8 @@ async fn kick_off_seconding( (CollationVersion::V2, Some(_)) | (CollationVersion::V1, _) => { let pvd = request_persisted_validation_data( ctx.sender(), - candidate_receipt.descriptor().relay_parent, - candidate_receipt.descriptor().para_id, + candidate_receipt.descriptor().relay_parent(), + candidate_receipt.descriptor().para_id(), ) .await?; ( @@ -1874,14 +1895,14 @@ async fn kick_off_seconding( gum::debug!( target: LOG_TARGET, candidate_hash = ?blocked_collation.candidate_receipt.hash(), - relay_parent = ?blocked_collation.candidate_receipt.descriptor.relay_parent, + relay_parent = ?blocked_collation.candidate_receipt.descriptor.relay_parent(), "Collation having parent head data hash {} is blocked from seconding. Waiting on its parent to be validated.", parent_head_data_hash ); state .blocked_from_seconding .entry(BlockedCollationId { - para_id: blocked_collation.candidate_receipt.descriptor.para_id, + para_id: blocked_collation.candidate_receipt.descriptor.para_id(), parent_head_data_hash, }) .or_insert_with(Vec::new) @@ -2024,12 +2045,14 @@ async fn handle_collation_fetch_response( }, Ok( request_v1::CollationFetchingResponse::Collation(receipt, _) | - request_v1::CollationFetchingResponse::CollationWithParentHeadData { receipt, .. }, - ) if receipt.descriptor().para_id != pending_collation.para_id => { + 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, expected_para_id = ?pending_collation.para_id, - got_para_id = ?receipt.descriptor().para_id, + got_para_id = ?receipt.descriptor().para_id(), peer_id = ?pending_collation.peer_id, "Got wrong para ID for requested collation." ); @@ -2086,3 +2109,35 @@ async fn handle_collation_fetch_response( state.metrics.on_request(metrics_result); result } + +// 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 86c8bcb6bdcd..7bc61dd4ebec 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 @@ -42,8 +42,10 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - CandidateReceipt, CollatorPair, CoreIndex, CoreState, GroupIndex, GroupRotationInfo, HeadData, - OccupiedCore, PersistedValidationData, ScheduledCore, ValidatorId, ValidatorIndex, + node_features, + vstaging::{CandidateReceiptV2 as CandidateReceipt, CoreState, OccupiedCore}, + CollatorPair, CoreIndex, GroupIndex, GroupRotationInfo, HeadData, NodeFeatures, + PersistedValidationData, ScheduledCore, ValidatorId, ValidatorIndex, }; use polkadot_primitives_test_helpers::{ dummy_candidate_descriptor, dummy_candidate_receipt_bad_sig, dummy_hash, @@ -77,6 +79,8 @@ struct TestState { group_rotation_info: GroupRotationInfo, cores: Vec, claim_queue: BTreeMap>, + node_features: NodeFeatures, + session_index: SessionIndex, } impl Default for TestState { @@ -121,7 +125,7 @@ impl Default for TestState { let mut d = dummy_candidate_descriptor(dummy_hash()); d.para_id = chain_ids[1]; - d + d.into() }, }), ]; @@ -131,6 +135,10 @@ impl Default for TestState { claim_queue.insert(CoreIndex(1), VecDeque::new()); claim_queue.insert(CoreIndex(2), [chain_ids[1]].into_iter().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, relay_parent, @@ -140,6 +148,8 @@ impl Default for TestState { group_rotation_info, cores, claim_queue, + node_features, + session_index: 1, } } } @@ -236,10 +246,44 @@ 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( +async fn respond_to_runtime_api_queries( virtual_overseer: &mut VirtualOverseer, test_state: &TestState, + hash: Hash, ) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + rp, + RuntimeApiRequest::SessionIndexForChild(tx) + )) => { + assert_eq!(rp, hash); + tx.send(Ok(test_state.session_index)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + rp, + RuntimeApiRequest::AsyncBackingParams(tx) + )) => { + assert_eq!(rp, hash); + tx.send(Err(ASYNC_BACKING_DISABLED_ERROR)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + rp, + RuntimeApiRequest::NodeFeatures(_, tx) + )) => { + assert_eq!(rp, hash); + tx.send(Ok(test_state.node_features.clone())).unwrap(); + } + ); + assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( @@ -253,9 +297,10 @@ async fn respond_to_core_info_queries( assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, + rp, RuntimeApiRequest::ValidatorGroups(tx), )) => { + assert_eq!(rp, hash); let _ = tx.send(Ok(( test_state.validator_groups.clone(), test_state.group_rotation_info.clone(), @@ -266,9 +311,10 @@ async fn respond_to_core_info_queries( assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( - _, + rp, RuntimeApiRequest::AvailabilityCores(tx), )) => { + assert_eq!(rp, hash); let _ = tx.send(Ok(test_state.cores.clone())); } ); @@ -276,19 +322,10 @@ async fn respond_to_core_info_queries( 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( - _, + rp, RuntimeApiRequest::ClaimQueue(tx), )) => { + assert_eq!(rp, hash); let _ = tx.send(Ok(test_state.claim_queue.clone())); } ); @@ -341,7 +378,7 @@ async fn assert_candidate_backing_second( incoming_pov, )) => { assert_eq!(expected_relay_parent, relay_parent); - assert_eq!(expected_para_id, candidate_receipt.descriptor.para_id); + assert_eq!(expected_para_id, candidate_receipt.descriptor.para_id()); assert_eq!(*expected_pov, incoming_pov); assert_eq!(pvd, received_pvd); candidate_receipt @@ -469,19 +506,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() { @@ -501,8 +525,8 @@ fn act_on_advertisement() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -549,8 +573,8 @@ fn act_on_advertisement_v2() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -591,8 +615,11 @@ fn act_on_advertisement_v2() { response_channel .send(Ok(( - request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()) - .encode(), + request_v1::CollationFetchingResponse::Collation( + candidate_a.clone().into(), + pov.clone(), + ) + .encode(), ProtocolName::from(""), ))) .expect("Sending response should succeed"); @@ -627,9 +654,8 @@ fn collator_reporting_works() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); let peer_c = PeerId::random(); @@ -744,8 +770,7 @@ fn fetch_one_collation_at_a_time() { // 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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, *hash).await; } let peer_b = PeerId::random(); @@ -793,8 +818,11 @@ fn fetch_one_collation_at_a_time() { candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); response_channel .send(Ok(( - request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()) - .encode(), + request_v1::CollationFetchingResponse::Collation( + candidate_a.clone().into(), + pov.clone(), + ) + .encode(), ProtocolName::from(""), ))) .expect("Sending response should succeed"); @@ -840,8 +868,7 @@ fn fetches_next_collation() { .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, *hash).await; } let peer_b = PeerId::random(); @@ -917,16 +944,22 @@ fn fetches_next_collation() { // First request finishes now: response_channel_non_exclusive .send(Ok(( - request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()) - .encode(), + request_v1::CollationFetchingResponse::Collation( + candidate_a.clone().into(), + pov.clone(), + ) + .encode(), ProtocolName::from(""), ))) .expect("Sending response should succeed"); response_channel .send(Ok(( - request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()) - .encode(), + request_v1::CollationFetchingResponse::Collation( + candidate_a.clone().into(), + pov.clone(), + ) + .encode(), ProtocolName::from(""), ))) .expect("Sending response should succeed"); @@ -959,8 +992,8 @@ fn reject_connection_to_next_group() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -1011,8 +1044,7 @@ fn fetch_next_collation_on_invalid_collation() { .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, *hash).await; } let peer_b = PeerId::random(); @@ -1055,8 +1087,11 @@ fn fetch_next_collation_on_invalid_collation() { candidate_a.descriptor.persisted_validation_data_hash = dummy_pvd().hash(); response_channel .send(Ok(( - request_v1::CollationFetchingResponse::Collation(candidate_a.clone(), pov.clone()) - .encode(), + request_v1::CollationFetchingResponse::Collation( + candidate_a.clone().into(), + pov.clone(), + ) + .encode(), ProtocolName::from(""), ))) .expect("Sending response should succeed"); @@ -1119,8 +1154,8 @@ fn inactive_disconnected() { ) .await; - assert_async_backing_params_request(&mut virtual_overseer, hash_a).await; - respond_to_core_info_queries(&mut virtual_overseer, &test_state).await; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -1173,8 +1208,7 @@ fn activity_extends_life() { .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, *hash).await; } let peer_b = PeerId::random(); @@ -1247,8 +1281,8 @@ fn disconnect_if_no_declare() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -1286,8 +1320,8 @@ fn disconnect_if_wrong_declare() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -1348,8 +1382,8 @@ fn delay_reputation_change() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -1434,8 +1468,8 @@ fn view_change_clears_old_collators() { ) .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, test_state.relay_parent) + .await; let peer_b = PeerId::random(); @@ -1459,8 +1493,7 @@ fn view_change_clears_old_collators() { .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; + respond_to_runtime_api_queries(&mut virtual_overseer, &test_state, hash_b).await; assert_collator_disconnect(&mut virtual_overseer, peer_b).await; 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 dff98e22e3db..eda26e8539a1 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,9 +20,10 @@ use super::*; use polkadot_node_subsystem::messages::ChainApiMessage; use polkadot_primitives::{ - AsyncBackingParams, BlockNumber, CandidateCommitments, CommittedCandidateReceipt, Header, - SigningContext, ValidatorId, + vstaging::{CommittedCandidateReceiptV2 as CommittedCandidateReceipt, MutateDescriptorV2}, + AsyncBackingParams, BlockNumber, CandidateCommitments, Header, SigningContext, ValidatorId, }; +use polkadot_primitives_test_helpers::dummy_committed_candidate_receipt_v2; use rstest::rstest; const ASYNC_BACKING_PARAMETERS: AsyncBackingParams = @@ -32,7 +33,7 @@ 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, @@ -73,16 +74,6 @@ async fn assert_assign_incoming( } ); - 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( @@ -117,14 +108,34 @@ pub(super) async fn update_view( overseer_recv(virtual_overseer).await, AllMessages::RuntimeApi(RuntimeApiMessage::Request( parent, + RuntimeApiRequest::SessionIndexForChild(tx) + )) => { + tx.send(Ok(test_state.session_index)).unwrap(); + (parent, new_view.get(&parent).copied().expect("Unknown parent requested")) + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, RuntimeApiRequest::AsyncBackingParams(tx), )) => { tx.send(Ok(ASYNC_BACKING_PARAMETERS)).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::NodeFeatures(_, tx) + )) => { + tx.send(Ok(test_state.node_features.clone())).unwrap(); + } + ); + + assert_construct_per_relay_parent( virtual_overseer, test_state, leaf_hash, @@ -193,7 +204,7 @@ 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( + assert_construct_per_relay_parent( virtual_overseer, test_state, hash, @@ -225,7 +236,7 @@ async fn send_seconded_statement( overseer_send( virtual_overseer, - CollatorProtocolMessage::Seconded(candidate.descriptor.relay_parent, stmt), + CollatorProtocolMessage::Seconded(candidate.descriptor.relay_parent(), stmt), ) .await; } @@ -374,7 +385,7 @@ fn v1_advertisement_accepted_and_seconded() { hrmp_watermark: 0, }; candidate.commitments_hash = commitments.hash(); - + let candidate: CandidateReceipt = candidate.into(); let pov = PoV { block_data: BlockData(vec![1]) }; response_channel @@ -406,7 +417,7 @@ fn v1_advertisement_accepted_and_seconded() { } #[test] -fn v1_advertisement_rejected_on_non_active_leave() { +fn v1_advertisement_rejected_on_non_active_leaf() { let test_state = TestState::default(); test_harness(ReputationAggregator::new(|_| true), |test_harness| async move { @@ -595,6 +606,7 @@ fn second_multiple_candidates_per_relay_parent() { 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(); @@ -750,7 +762,7 @@ fn fetched_collation_sanity_check() { hrmp_watermark: 0, }; candidate.commitments_hash = commitments.hash(); - + let candidate: CandidateReceipt = candidate.into(); let candidate_hash = CandidateHash(Hash::zero()); let parent_head_data_hash = Hash::zero(); @@ -845,7 +857,6 @@ fn sanity_check_invalid_parent_head_data() { let mut candidate = dummy_candidate_receipt_bad_sig(head_c, Some(Default::default())); candidate.descriptor.para_id = test_state.chain_ids[0]; - let commitments = CandidateCommitments { head_data: HeadData(vec![1, 2, 3]), horizontal_messages: Default::default(), @@ -864,6 +875,7 @@ fn sanity_check_invalid_parent_head_data() { pvd.parent_head = parent_head_data; candidate.descriptor.persisted_validation_data_hash = pvd.hash(); + let candidate: CandidateReceipt = candidate.into(); let candidate_hash = candidate.hash(); @@ -1068,6 +1080,7 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { processed_downward_messages: 0, hrmp_watermark: 0, }; + let mut candidate_b: CandidateReceipt = candidate_b.into(); candidate_b.commitments_hash = candidate_b_commitments.hash(); let candidate_b_hash = candidate_b.hash(); @@ -1134,6 +1147,7 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { relay_parent_storage_root: Default::default(), } .hash(); + let mut candidate_a: CandidateReceipt = candidate_a.into(); let candidate_a_commitments = CandidateCommitments { head_data: HeadData(vec![1]), horizontal_messages: Default::default(), @@ -1144,6 +1158,7 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { }; candidate_a.commitments_hash = candidate_a_commitments.hash(); + let candidate_a: CandidateReceipt = candidate_a.into(); let candidate_a_hash = candidate_a.hash(); advertise_collation( @@ -1208,7 +1223,7 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { incoming_pov, )) => { assert_eq!(head_c, relay_parent); - assert_eq!(test_state.chain_ids[0], candidate_receipt.descriptor.para_id); + assert_eq!(test_state.chain_ids[0], candidate_receipt.descriptor.para_id()); assert_eq!(PoV { block_data: BlockData(vec![2]) }, incoming_pov); assert_eq!(PersistedValidationData:: { parent_head: HeadData(vec![0]), @@ -1261,7 +1276,7 @@ fn child_blocked_from_seconding_by_parent(#[case] valid_parent: bool) { incoming_pov, )) => { assert_eq!(head_c, relay_parent); - assert_eq!(test_state.chain_ids[0], candidate_receipt.descriptor.para_id); + assert_eq!(test_state.chain_ids[0], candidate_receipt.descriptor.para_id()); assert_eq!(PoV { block_data: BlockData(vec![1]) }, incoming_pov); assert_eq!(PersistedValidationData:: { parent_head: HeadData(vec![1]), @@ -1310,3 +1325,223 @@ 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, &test_state, vec![(head_b, head_b_num)], 1).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 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, &test_state, vec![(head_b, head_b_num)], 1).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 + }); +} diff --git a/polkadot/node/network/dispute-distribution/src/receiver/batches/batch.rs b/polkadot/node/network/dispute-distribution/src/receiver/batches/batch.rs index 11380b7c072e..c911b4bc4ae6 100644 --- a/polkadot/node/network/dispute-distribution/src/receiver/batches/batch.rs +++ b/polkadot/node/network/dispute-distribution/src/receiver/batches/batch.rs @@ -22,7 +22,7 @@ use polkadot_node_network_protocol::{ PeerId, }; use polkadot_node_primitives::SignedDisputeStatement; -use polkadot_primitives::{CandidateReceipt, ValidatorIndex}; +use polkadot_primitives::{vstaging::CandidateReceiptV2 as CandidateReceipt, ValidatorIndex}; use crate::receiver::{BATCH_COLLECTING_INTERVAL, MIN_KEEP_BATCH_ALIVE_VOTES}; diff --git a/polkadot/node/network/dispute-distribution/src/receiver/batches/mod.rs b/polkadot/node/network/dispute-distribution/src/receiver/batches/mod.rs index 76c7683d1574..13b42aff1f30 100644 --- a/polkadot/node/network/dispute-distribution/src/receiver/batches/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/receiver/batches/mod.rs @@ -22,7 +22,7 @@ use std::{ use futures::future::pending; use polkadot_node_network_protocol::request_response::DISPUTE_REQUEST_TIMEOUT; -use polkadot_primitives::{CandidateHash, CandidateReceipt}; +use polkadot_primitives::{vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash}; use crate::{ receiver::batches::{batch::TickResult, waiting_queue::PendingWake}, diff --git a/polkadot/node/network/dispute-distribution/src/receiver/mod.rs b/polkadot/node/network/dispute-distribution/src/receiver/mod.rs index 77c1e41aac05..b21965fc7004 100644 --- a/polkadot/node/network/dispute-distribution/src/receiver/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/receiver/mod.rs @@ -334,7 +334,7 @@ where .runtime .get_session_info_by_index( &mut self.sender, - payload.0.candidate_receipt.descriptor.relay_parent, + payload.0.candidate_receipt.descriptor.relay_parent(), payload.0.session_index, ) .await?; diff --git a/polkadot/node/network/dispute-distribution/src/sender/send_task.rs b/polkadot/node/network/dispute-distribution/src/sender/send_task.rs index 54ccd10789d0..f607c9431513 100644 --- a/polkadot/node/network/dispute-distribution/src/sender/send_task.rs +++ b/polkadot/node/network/dispute-distribution/src/sender/send_task.rs @@ -234,7 +234,7 @@ impl SendTask { runtime: &mut RuntimeInfo, active_sessions: &HashMap, ) -> Result> { - let ref_head = self.request.0.candidate_receipt.descriptor.relay_parent; + let ref_head = self.request.0.candidate_receipt.descriptor.relay_parent(); // Retrieve all authorities which participated in the parachain consensus of the session // in which the candidate was backed. let info = runtime diff --git a/polkadot/node/network/dispute-distribution/src/tests/mock.rs b/polkadot/node/network/dispute-distribution/src/tests/mock.rs index baa857e2eb68..52659ae9e002 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mock.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mock.rs @@ -33,10 +33,10 @@ use sp_keystore::{Keystore, KeystorePtr}; use polkadot_node_primitives::{DisputeMessage, SignedDisputeStatement}; use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateHash, CandidateReceipt, Hash, SessionIndex, SessionInfo, - ValidatorId, ValidatorIndex, + vstaging::CandidateReceiptV2 as CandidateReceipt, AuthorityDiscoveryId, CandidateHash, Hash, + SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, }; -use polkadot_primitives_test_helpers::dummy_candidate_descriptor; +use polkadot_primitives_test_helpers::dummy_candidate_descriptor_v2; use crate::LOG_TARGET; @@ -116,7 +116,7 @@ pub static MOCK_NEXT_SESSION_INFO: LazyLock = LazyLock::new(|| Sess pub fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { CandidateReceipt { - descriptor: dummy_candidate_descriptor(relay_parent), + descriptor: dummy_candidate_descriptor_v2(relay_parent), commitments_hash: Hash::random(), } } diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs index 60820e62ca2d..5306b22828cc 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs @@ -57,8 +57,8 @@ use polkadot_node_subsystem_test_helpers::{ subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::{ - AuthorityDiscoveryId, Block, CandidateHash, CandidateReceipt, ExecutorParams, Hash, - NodeFeatures, SessionIndex, SessionInfo, + vstaging::CandidateReceiptV2 as CandidateReceipt, AuthorityDiscoveryId, Block, CandidateHash, + ExecutorParams, Hash, NodeFeatures, SessionIndex, SessionInfo, }; use self::mock::{ diff --git a/polkadot/node/network/protocol/src/request_response/mod.rs b/polkadot/node/network/protocol/src/request_response/mod.rs index b498de55dce4..296c462b508d 100644 --- a/polkadot/node/network/protocol/src/request_response/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/mod.rs @@ -123,10 +123,12 @@ const DEFAULT_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_secs(1); /// Timeout for requesting availability chunks. pub const CHUNK_REQUEST_TIMEOUT: Duration = DEFAULT_REQUEST_TIMEOUT_CONNECTED; -/// This timeout is based on what seems sensible from a time budget perspective, considering 6 -/// second block time. This is going to be tough, if we have multiple forks and large PoVs, but we -/// only have so much time. -const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(1200); +/// This timeout is based on the following parameters, assuming we use asynchronous backing with no +/// time budget within a relay block: +/// - 500 Mbit/s networking speed +/// - 10 MB PoV +/// - 10 parallel executions +const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(2000); /// We want timeout statement requests fast, so we don't waste time on slow nodes. Responders will /// try their best to either serve within that timeout or return an error immediately. (We need to diff --git a/polkadot/node/network/protocol/src/request_response/v1.rs b/polkadot/node/network/protocol/src/request_response/v1.rs index 80721f1884af..4f28d4cbf2d8 100644 --- a/polkadot/node/network/protocol/src/request_response/v1.rs +++ b/polkadot/node/network/protocol/src/request_response/v1.rs @@ -22,8 +22,11 @@ use polkadot_node_primitives::{ AvailableData, DisputeMessage, ErasureChunk, PoV, Proof, UncheckedDisputeMessage, }; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, - ValidatorIndex, + vstaging::{ + CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, + }, + CandidateHash, Hash, HeadData, Id as ParaId, ValidatorIndex, }; use super::{IsRequest, Protocol}; diff --git a/polkadot/node/network/protocol/src/request_response/v2.rs b/polkadot/node/network/protocol/src/request_response/v2.rs index ae65b39cd406..834870e5b908 100644 --- a/polkadot/node/network/protocol/src/request_response/v2.rs +++ b/polkadot/node/network/protocol/src/request_response/v2.rs @@ -20,8 +20,8 @@ use codec::{Decode, Encode}; use polkadot_node_primitives::ErasureChunk; use polkadot_primitives::{ - CandidateHash, CommittedCandidateReceipt, Hash, Id as ParaId, PersistedValidationData, - UncheckedSignedStatement, ValidatorIndex, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateHash, Hash, + Id as ParaId, PersistedValidationData, UncheckedSignedStatement, ValidatorIndex, }; use super::{v1, IsRequest, Protocol}; diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index 2a9773ddde4b..de07937ffb0a 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -40,9 +40,11 @@ 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 } +rstest = { 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/legacy_v1/mod.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs index 8270b9809194..bd6d4ebe755c 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -37,9 +37,10 @@ use polkadot_node_subsystem::{ overseer, ActivatedLeaf, StatementDistributionSenderTrait, }; use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateHash, CommittedCandidateReceipt, CompactStatement, Hash, - Id as ParaId, IndexedVec, OccupiedCoreAssumption, PersistedValidationData, SignedStatement, - SigningContext, UncheckedSignedStatement, ValidatorId, ValidatorIndex, ValidatorSignature, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, AuthorityDiscoveryId, + CandidateHash, CompactStatement, Hash, Id as ParaId, IndexedVec, OccupiedCoreAssumption, + PersistedValidationData, SignedStatement, SigningContext, UncheckedSignedStatement, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use futures::{ @@ -1641,7 +1642,7 @@ async fn handle_incoming_message<'a, Context>( // In case of `Valid` we should have it cached prior, therefore this performs // no Runtime API calls and always returns `Ok(Some(_))`. let pvd = if let Statement::Seconded(receipt) = statement.payload() { - let para_id = receipt.descriptor.para_id; + let para_id = receipt.descriptor.para_id(); // Either call the Runtime API or check that validation data is cached. let result = active_head .fetch_persisted_validation_data(ctx.sender(), relay_parent, para_id) diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs index c0346adfe101..69bcbac76b70 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs @@ -29,7 +29,9 @@ use polkadot_node_network_protocol::{ PeerId, UnifiedReputationChange, }; use polkadot_node_subsystem_util::TimeoutExt; -use polkadot_primitives::{CandidateHash, CommittedCandidateReceipt, Hash}; +use polkadot_primitives::{ + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateHash, Hash, +}; use crate::{ legacy_v1::{COST_WRONG_HASH, LOG_TARGET}, diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs index 8d1683759a03..03e1dc059989 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/responder.rs @@ -29,7 +29,9 @@ use polkadot_node_network_protocol::{ }, PeerId, UnifiedReputationChange as Rep, }; -use polkadot_primitives::{CandidateHash, CommittedCandidateReceipt, Hash}; +use polkadot_primitives::{ + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateHash, Hash, +}; use crate::LOG_TARGET; diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index 5e00fb96d74f..d2fd016ec2f1 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -47,7 +47,8 @@ use polkadot_primitives::{ SessionInfo, ValidationCode, }; use polkadot_primitives_test_helpers::{ - dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng, + dummy_committed_candidate_receipt, dummy_committed_candidate_receipt_v2, dummy_hash, + AlwaysZeroRng, }; use sc_keystore::LocalKeystore; use sc_network::ProtocolName; @@ -140,7 +141,7 @@ fn active_head_accepts_only_2_seconded_per_validator() { // note A let a_seconded_val_0 = SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate_a.clone()), + Statement::Seconded(candidate_a.into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -167,7 +168,7 @@ fn active_head_accepts_only_2_seconded_per_validator() { // note B let statement = SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate_b.clone()), + Statement::Seconded(candidate_b.clone().into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -184,7 +185,7 @@ fn active_head_accepts_only_2_seconded_per_validator() { // note C (beyond 2 - ignored) let statement = SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate_c.clone()), + Statement::Seconded(candidate_c.clone().into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -202,7 +203,7 @@ fn active_head_accepts_only_2_seconded_per_validator() { // note B (new validator) let statement = SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate_b.clone()), + Statement::Seconded(candidate_b.into()), &signing_context, ValidatorIndex(1), &bob_public.into(), @@ -219,7 +220,7 @@ fn active_head_accepts_only_2_seconded_per_validator() { // note C (new validator) let statement = SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate_c.clone()), + Statement::Seconded(candidate_c.into()), &signing_context, ValidatorIndex(1), &bob_public.into(), @@ -470,7 +471,7 @@ fn peer_view_update_sends_messages() { let statement = SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate.clone()), + Statement::Seconded(candidate.clone().into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -612,7 +613,7 @@ fn circulated_statement_goes_to_all_peers_with_view() { let mut c = dummy_committed_candidate_receipt(dummy_hash()); c.descriptor.relay_parent = hash_b; c.descriptor.para_id = ParaId::from(1_u32); - c + c.into() }; let peer_a = PeerId::random(); @@ -746,7 +747,7 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { let mut c = dummy_committed_candidate_receipt(dummy_hash()); c.descriptor.relay_parent = hash_a; c.descriptor.para_id = PARA_ID; - c + c.into() }; let peer_a = PeerId::random(); @@ -1199,7 +1200,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate.clone()), + Statement::Seconded(candidate.clone().into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -1337,7 +1338,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( let bad_candidate = { let mut bad = candidate.clone(); bad.descriptor.para_id = 0xeadbeaf.into(); - bad + bad.into() }; let response = StatementFetchingResponse::Statement(bad_candidate); outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap(); @@ -1391,7 +1392,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( assert_eq!(req.candidate_hash, metadata.candidate_hash); // On retry, we should have reverse order: assert_eq!(outgoing.peer, Recipient::Peer(peer_c)); - let response = StatementFetchingResponse::Statement(candidate.clone()); + let response = StatementFetchingResponse::Statement(candidate.clone().into()); outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap(); } ); @@ -1517,7 +1518,7 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( req_cfg.inbound_queue.as_mut().unwrap().send(req).await.unwrap(); let StatementFetchingResponse::Statement(committed) = Decode::decode(&mut response_rx.await.unwrap().result.unwrap().as_ref()).unwrap(); - assert_eq!(committed, candidate); + assert_eq!(committed, candidate.into()); handle.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; }; @@ -1744,7 +1745,7 @@ fn delay_reputation_changes() { SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate.clone()), + Statement::Seconded(candidate.clone().into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -1884,7 +1885,7 @@ fn delay_reputation_changes() { bad.descriptor.para_id = 0xeadbeaf.into(); bad }; - let response = StatementFetchingResponse::Statement(bad_candidate); + let response = StatementFetchingResponse::Statement(bad_candidate.into()); outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap(); } ); @@ -1928,7 +1929,7 @@ fn delay_reputation_changes() { assert_eq!(req.candidate_hash, metadata.candidate_hash); // On retry, we should have reverse order: assert_eq!(outgoing.peer, Recipient::Peer(peer_c)); - let response = StatementFetchingResponse::Statement(candidate.clone()); + let response = StatementFetchingResponse::Statement(candidate.clone().into()); outgoing.pending_response.send(Ok((response.encode(), ProtocolName::from("")))).unwrap(); } ); @@ -2288,7 +2289,7 @@ fn share_prioritizes_backing_group() { SignedFullStatementWithPVD::sign( &keystore, - Statement::Seconded(candidate.clone()).supply_pvd(pvd), + Statement::Seconded(candidate.clone().into()).supply_pvd(pvd), &signing_context, ValidatorIndex(4), &ferdie_public.into(), @@ -2352,7 +2353,7 @@ fn share_prioritizes_backing_group() { req_cfg.inbound_queue.as_mut().unwrap().send(req).await.unwrap(); let StatementFetchingResponse::Statement(committed) = Decode::decode(&mut response_rx.await.unwrap().result.unwrap().as_ref()).unwrap(); - assert_eq!(committed, candidate); + assert_eq!(committed, candidate.into()); handle.send(FromOrchestra::Signal(OverseerSignal::Conclude)).await; }; @@ -2514,7 +2515,7 @@ fn peer_cant_flood_with_large_statements() { SignedFullStatement::sign( &keystore, - Statement::Seconded(candidate.clone()), + Statement::Seconded(candidate.clone().into()), &signing_context, ValidatorIndex(0), &alice_public.into(), @@ -2595,7 +2596,7 @@ fn handle_multiple_seconded_statements() { let relay_parent_hash = Hash::repeat_byte(1); let pvd = dummy_pvd(); - let candidate = dummy_committed_candidate_receipt(relay_parent_hash); + let candidate = dummy_committed_candidate_receipt_v2(relay_parent_hash); let candidate_hash = candidate.hash(); // We want to ensure that our peers are not lucky diff --git a/polkadot/node/network/statement-distribution/src/v2/candidates.rs b/polkadot/node/network/statement-distribution/src/v2/candidates.rs index a4f2455c2840..1a37d2ea086a 100644 --- a/polkadot/node/network/statement-distribution/src/v2/candidates.rs +++ b/polkadot/node/network/statement-distribution/src/v2/candidates.rs @@ -28,8 +28,8 @@ use polkadot_node_network_protocol::PeerId; use polkadot_node_subsystem::messages::HypotheticalCandidate; use polkadot_primitives::{ - CandidateHash, CommittedCandidateReceipt, GroupIndex, Hash, Id as ParaId, - PersistedValidationData, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateHash, GroupIndex, + Hash, Id as ParaId, PersistedValidationData, }; use std::{ @@ -154,8 +154,8 @@ impl Candidates { assigned_group: GroupIndex, ) -> Option { let parent_hash = persisted_validation_data.parent_head.hash(); - let relay_parent = candidate_receipt.descriptor().relay_parent; - let para_id = candidate_receipt.descriptor().para_id; + let relay_parent = candidate_receipt.descriptor.relay_parent(); + let para_id = candidate_receipt.descriptor.para_id(); let prev_state = self.candidates.insert( candidate_hash, @@ -530,12 +530,12 @@ pub struct ConfirmedCandidate { impl ConfirmedCandidate { /// Get the relay-parent of the candidate. pub fn relay_parent(&self) -> Hash { - self.receipt.descriptor().relay_parent + self.receipt.descriptor.relay_parent() } /// Get the para-id of the candidate. pub fn para_id(&self) -> ParaId { - self.receipt.descriptor().para_id + self.receipt.descriptor.para_id() } /// Get the underlying candidate receipt. diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index f9c2d0ddbae8..6bb49e5de13d 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -46,13 +46,16 @@ 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::{ - AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, - GroupRotationInfo, Hash, Id as ParaId, IndexedVec, SessionIndex, SessionInfo, SignedStatement, - SigningContext, UncheckedSignedStatement, ValidatorId, ValidatorIndex, + 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, }; use sp_keystore::KeystorePtr; @@ -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 { @@ -1201,7 +1212,7 @@ pub(crate) async fn share_local_statement( // have the candidate. Sanity: check the para-id is valid. let expected = match statement.payload() { FullStatementWithPVD::Seconded(ref c, _) => - Some((c.descriptor().para_id, c.descriptor().relay_parent)), + Some((c.descriptor.para_id(), c.descriptor.relay_parent())), FullStatementWithPVD::Valid(hash) => state.candidates.get_confirmed(&hash).map(|c| (c.para_id(), c.relay_parent())), }; @@ -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`. @@ -2277,13 +2265,13 @@ async fn fragment_chain_update_inner( } = hypo { let confirmed_candidate = state.candidates.get_confirmed(&candidate_hash); - let prs = state.per_relay_parent.get_mut(&receipt.descriptor().relay_parent); + let prs = state.per_relay_parent.get_mut(&receipt.descriptor.relay_parent()); if let (Some(confirmed), Some(prs)) = (confirmed_candidate, prs) { let per_session = state.per_session.get(&prs.session); let group_index = confirmed.group_index(); // Sanity check if group_index is valid for this para at relay parent. - let Some(expected_groups) = prs.groups_per_para.get(&receipt.descriptor().para_id) + let Some(expected_groups) = prs.groups_per_para.get(&receipt.descriptor.para_id()) else { continue }; @@ -2296,7 +2284,7 @@ async fn fragment_chain_update_inner( ctx, candidate_hash, confirmed.group_index(), - &receipt.descriptor().relay_parent, + &receipt.descriptor.relay_parent(), prs, confirmed, per_session, @@ -2888,7 +2876,7 @@ pub(crate) async fn handle_backed_candidate_message( ctx, state, confirmed.para_id(), - confirmed.candidate_receipt().descriptor().para_head, + confirmed.candidate_receipt().descriptor.para_head(), ) .await; } @@ -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 b8ed34d26c8a..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; @@ -47,9 +49,9 @@ use polkadot_node_network_protocol::{ PeerId, UnifiedReputationChange as Rep, }; use polkadot_primitives::{ - CandidateHash, CommittedCandidateReceipt, CompactStatement, GroupIndex, Hash, Id as ParaId, - PersistedValidationData, SessionIndex, SignedStatement, SigningContext, ValidatorId, - ValidatorIndex, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateHash, + CompactStatement, GroupIndex, Hash, Id as ParaId, PersistedValidationData, SessionIndex, + SignedStatement, SigningContext, ValidatorId, ValidatorIndex, }; use futures::{future::BoxFuture, prelude::*, stream::FuturesUnordered}; @@ -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() + if response.candidate_receipt.descriptor.relay_parent() != identifier.relay_parent { + return invalid_candidate_output(COST_INVALID_RESPONSE) } - if response.candidate_receipt.descriptor.persisted_validation_data_hash != + 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, + 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 @@ -1019,6 +1071,7 @@ mod tests { candidate_receipt.descriptor.persisted_validation_data_hash = persisted_validation_data.hash(); let candidate = candidate_receipt.hash(); + let candidate_receipt: CommittedCandidateReceipt = candidate_receipt.into(); let requested_peer_1 = PeerId::random(); let requested_peer_2 = PeerId::random(); @@ -1074,7 +1127,7 @@ mod tests { requested_peer: requested_peer_1, props: request_properties.clone(), response: Ok(AttestedCandidateResponse { - candidate_receipt: candidate_receipt.clone(), + candidate_receipt: candidate_receipt.clone().into(), persisted_validation_data: persisted_validation_data.clone(), statements, }), @@ -1090,6 +1143,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask.clone(), + &Default::default(), + false, ); assert_eq!( output, @@ -1114,7 +1169,7 @@ mod tests { requested_peer: requested_peer_2, props: request_properties, response: Ok(AttestedCandidateResponse { - candidate_receipt: candidate_receipt.clone(), + candidate_receipt: candidate_receipt.clone().into(), persisted_validation_data: persisted_validation_data.clone(), statements, }), @@ -1129,6 +1184,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask, + &Default::default(), + false, ); assert_eq!( output, @@ -1197,7 +1254,7 @@ mod tests { requested_peer, props: request_properties, response: Ok(AttestedCandidateResponse { - candidate_receipt: candidate_receipt.clone(), + candidate_receipt: candidate_receipt.clone().into(), persisted_validation_data: persisted_validation_data.clone(), statements, }), @@ -1213,6 +1270,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask, + &Default::default(), + false, ); assert_eq!( output, @@ -1236,6 +1295,7 @@ mod tests { candidate_receipt.descriptor.persisted_validation_data_hash = persisted_validation_data.hash(); let candidate = candidate_receipt.hash(); + let candidate_receipt: CommittedCandidateReceipt = candidate_receipt.into(); let requested_peer = PeerId::random(); let identifier = request_manager @@ -1294,6 +1354,8 @@ mod tests { validator_key_lookup, allowed_para_lookup, disabled_mask, + &Default::default(), + false, ); assert_eq!( output, @@ -1417,7 +1479,7 @@ mod tests { requested_peer: requested_peer_1, props: request_properties.clone(), response: Ok(AttestedCandidateResponse { - candidate_receipt: candidate_receipt_1.clone(), + candidate_receipt: candidate_receipt_1.clone().into(), persisted_validation_data: persisted_validation_data_1.clone(), statements, }), @@ -1432,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 119dc832d13a..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::{ - AssignmentPair, AsyncBackingParams, Block, BlockNumber, CommittedCandidateReceipt, CoreState, - 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/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index c2cb1817312c..f2cf60280b72 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -24,14 +24,16 @@ use orchestra::async_trait; use std::time::Duration; use polkadot_node_primitives::{BlockData, PoV}; -use polkadot_node_subsystem_types::messages::CandidateValidationMessage; +use polkadot_node_subsystem_types::messages::{CandidateValidationMessage, PvfExecKind}; use polkadot_overseer::{ self as overseer, dummy::dummy_overseer_builder, gen::{FromOrchestra, SpawnedSubsystem}, HeadSupportsParachains, SubsystemError, }; -use polkadot_primitives::{CandidateReceipt, Hash, PersistedValidationData, PvfExecKind}; +use polkadot_primitives::{ + vstaging::CandidateReceiptV2 as CandidateReceipt, Hash, PersistedValidationData, +}; use polkadot_primitives_test_helpers::{ dummy_candidate_descriptor, dummy_hash, dummy_validation_code, }; @@ -71,7 +73,7 @@ impl Subsystem1 { let (tx, _) = oneshot::channel(); let candidate_receipt = CandidateReceipt { - descriptor: dummy_candidate_descriptor(dummy_hash()), + descriptor: dummy_candidate_descriptor(dummy_hash()).into(), commitments_hash: Hash::zero(), }; @@ -81,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 47c26186b518..0b9b783ef9b1 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -25,14 +25,15 @@ use polkadot_node_primitives::{ }; use polkadot_node_subsystem_test_helpers::mock::{dummy_unpin_handle, new_leaf}; use polkadot_node_subsystem_types::messages::{ - NetworkBridgeEvent, ReportPeerMessage, RuntimeApiRequest, + NetworkBridgeEvent, PvfExecKind, ReportPeerMessage, RuntimeApiRequest, }; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CollatorPair, Id as ParaId, InvalidDisputeStatementKind, - PersistedValidationData, PvfExecKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, + vstaging::CandidateReceiptV2, CandidateHash, CollatorPair, Id as ParaId, + InvalidDisputeStatementKind, PersistedValidationData, SessionIndex, ValidDisputeStatementKind, + ValidatorIndex, }; use polkadot_primitives_test_helpers::{ - dummy_candidate_descriptor, dummy_candidate_receipt, dummy_hash, dummy_validation_code, + dummy_candidate_descriptor, dummy_candidate_receipt_v2, dummy_hash, dummy_validation_code, }; use crate::{ @@ -98,8 +99,8 @@ where let mut c: usize = 0; loop { if c < 10 { - let candidate_receipt = CandidateReceipt { - descriptor: dummy_candidate_descriptor(dummy_hash()), + let candidate_receipt = CandidateReceiptV2 { + descriptor: dummy_candidate_descriptor(dummy_hash()).into(), commitments_hash: dummy_hash(), }; @@ -110,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; @@ -799,8 +800,8 @@ where fn test_candidate_validation_msg() -> CandidateValidationMessage { let (response_sender, _) = oneshot::channel(); let pov = Arc::new(PoV { block_data: BlockData(Vec::new()) }); - let candidate_receipt = CandidateReceipt { - descriptor: dummy_candidate_descriptor(dummy_hash()), + let candidate_receipt = CandidateReceiptV2 { + descriptor: dummy_candidate_descriptor(dummy_hash()).into(), commitments_hash: Hash::zero(), }; @@ -810,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, } } @@ -859,7 +860,7 @@ fn test_statement_distribution_msg() -> StatementDistributionMessage { fn test_availability_recovery_msg() -> AvailabilityRecoveryMessage { let (sender, _) = oneshot::channel(); AvailabilityRecoveryMessage::RecoverAvailableData( - dummy_candidate_receipt(dummy_hash()), + dummy_candidate_receipt_v2(dummy_hash()), Default::default(), None, None, @@ -918,7 +919,7 @@ fn test_dispute_coordinator_msg() -> DisputeCoordinatorMessage { fn test_dispute_distribution_msg() -> DisputeDistributionMessage { let dummy_dispute_message = UncheckedDisputeMessage { - candidate_receipt: dummy_candidate_receipt(dummy_hash()), + candidate_receipt: dummy_candidate_receipt_v2(dummy_hash()), session_index: 0, invalid_vote: InvalidDisputeVote { validator_index: ValidatorIndex(0), diff --git a/polkadot/node/primitives/src/disputes/message.rs b/polkadot/node/primitives/src/disputes/message.rs index f9dec073bf50..d32ed4dadb6e 100644 --- a/polkadot/node/primitives/src/disputes/message.rs +++ b/polkadot/node/primitives/src/disputes/message.rs @@ -25,7 +25,8 @@ use codec::{Decode, Encode}; use super::{InvalidDisputeVote, SignedDisputeStatement, ValidDisputeVote}; use polkadot_primitives::{ - CandidateReceipt, DisputeStatement, SessionIndex, SessionInfo, ValidatorIndex, + vstaging::CandidateReceiptV2 as CandidateReceipt, DisputeStatement, SessionIndex, SessionInfo, + ValidatorIndex, }; /// A dispute initiating/participating message that have been built from signed diff --git a/polkadot/node/primitives/src/disputes/mod.rs b/polkadot/node/primitives/src/disputes/mod.rs index 0f08b4733654..71e2f0b16be3 100644 --- a/polkadot/node/primitives/src/disputes/mod.rs +++ b/polkadot/node/primitives/src/disputes/mod.rs @@ -25,9 +25,9 @@ use sp_application_crypto::AppCrypto; use sp_keystore::{Error as KeystoreError, KeystorePtr}; use polkadot_primitives::{ - CandidateHash, CandidateReceipt, CompactStatement, DisputeStatement, EncodeAs, - InvalidDisputeStatementKind, SessionIndex, SigningContext, UncheckedSigned, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + vstaging::CandidateReceiptV2 as CandidateReceipt, CandidateHash, CompactStatement, + DisputeStatement, EncodeAs, InvalidDisputeStatementKind, SessionIndex, SigningContext, + UncheckedSigned, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; /// `DisputeMessage` and related types. diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 99d3a3e515b8..6985e86098b0 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -30,10 +30,10 @@ use futures::Future; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use polkadot_primitives::{ - BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, ChunkIndex, CollatorPair, - CommittedCandidateReceipt, CompactStatement, CoreIndex, EncodeAs, Hash, HashT, HeadData, - Id as ParaId, PersistedValidationData, SessionIndex, Signed, UncheckedSigned, ValidationCode, - ValidationCodeHash, MAX_CODE_SIZE, MAX_POV_SIZE, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, BlakeTwo256, BlockNumber, + CandidateCommitments, CandidateHash, ChunkIndex, CollatorPair, CompactStatement, CoreIndex, + EncodeAs, Hash, HashT, HeadData, Id as ParaId, PersistedValidationData, SessionIndex, Signed, + UncheckedSigned, ValidationCode, ValidationCodeHash, MAX_CODE_SIZE, MAX_POV_SIZE, }; pub use sp_consensus_babe::{ AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch, @@ -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.0"; +pub const NODE_VERSION: &'static str = "1.16.1"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: @@ -348,6 +348,10 @@ pub enum InvalidCandidate { CodeHashMismatch, /// Validation has generated different candidate commitments. CommitmentsHashMismatch, + /// The candidate receipt contains an invalid session index. + InvalidSessionIndex, + /// The candidate receipt contains an invalid core index. + InvalidCoreIndex, } /// Result of the validation of the candidate. diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 8d50b54b2fdc..6e8eade21a43 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -140,7 +140,6 @@ polkadot-node-subsystem-test-helpers = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } sp-tracing = { workspace = true } assert_matches = { workspace = true } -serial_test = { workspace = true } tempfile = { workspace = true } [features] @@ -200,6 +199,7 @@ runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "polkadot-test-client/runtime-benchmarks", @@ -217,7 +217,10 @@ try-runtime = [ "sp-runtime/try-runtime", "westend-runtime?/try-runtime", ] -fast-runtime = ["rococo-runtime?/fast-runtime", "westend-runtime?/fast-runtime"] +fast-runtime = [ + "rococo-runtime?/fast-runtime", + "westend-runtime?/fast-runtime", +] malus = ["full-node"] runtime-metrics = [ diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 4dcff2078419..0cf16edc03cc 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -79,53 +79,6 @@ macro_rules! identify_chain { }; } -/// Generates `System::Remark` extrinsics for the benchmarks. -/// -/// Note: Should only be used for benchmarking. -pub struct RemarkBuilder { - client: Arc, - chain: Chain, -} - -impl RemarkBuilder { - /// Creates a new [`Self`] from the given client. - pub fn new(client: Arc, chain: Chain) -> Self { - Self { client, chain } - } -} - -impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { - fn pallet(&self) -> &str { - "system" - } - - fn extrinsic(&self) -> &str { - "remark" - } - - fn build(&self, nonce: u32) -> std::result::Result { - // We apply the extrinsic directly, so let's take some random period. - let period = 128; - let genesis = self.client.usage_info().chain.best_hash; - let signer = Sr25519Keyring::Bob.pair(); - let current_block = 0; - - identify_chain! { - self.chain, - nonce, - current_block, - period, - genesis, - signer, - { - runtime::RuntimeCall::System( - runtime::SystemCall::remark { remark: vec![] } - ) - }, - } - } -} - /// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks. /// /// Note: Should only be used for benchmarking. @@ -189,7 +142,7 @@ fn westend_sign_call( use sp_core::Pair; use westend_runtime as runtime; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -202,11 +155,12 @@ fn westend_sign_call( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), frame_metadata_hash_extension::CheckMetadataHash::::new(false), - ); + ) + .into(); let payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -225,7 +179,7 @@ fn westend_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature), - extra, + tx_ext, ) .into() } @@ -243,7 +197,7 @@ fn rococo_sign_call( use rococo_runtime as runtime; use sp_core::Pair; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -256,11 +210,12 @@ fn rococo_sign_call( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), frame_metadata_hash_extension::CheckMetadataHash::::new(false), - ); + ) + .into(); let payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -279,7 +234,7 @@ fn rococo_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature), - extra, + tx_ext, ) .into() } diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index fe360e7b8c76..3866c6950e09 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -27,10 +27,6 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "westend-native")] use westend_runtime as westend; -use polkadot_primitives::{AccountId, AccountPublic}; -use sp_core::{Pair, Public}; -use sp_runtime::traits::IdentifyAccount; - #[cfg(feature = "westend-native")] const WESTEND_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; #[cfg(feature = "rococo-native")] @@ -257,18 +253,3 @@ pub fn versi_local_testnet_config() -> Result { .with_protocol_id("versi") .build()) } - -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 9515dd231138..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}; @@ -450,7 +450,7 @@ fn new_partial( FullBackend, ChainSelection, sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ( impl Fn( polkadot_rpc::SubscriptionTaskExecutor, @@ -478,12 +478,15 @@ fn new_partial( where ChainSelection: 'static + SelectChain, { - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let grandpa_hard_forks = if config.chain_spec.is_kusama() { @@ -756,13 +759,12 @@ pub fn new_full< Some(backoff) }; - // Running approval voting in parallel is enabled by default on all networks except Polkadot and - // Kusama, unless explicitly enabled by the commandline option. + // Running approval voting in parallel is enabled by default on all networks except Polkadot + // unless explicitly enabled by the commandline option. // This is meant to be temporary until we have enough confidence in the new system to enable it // by default on all networks. - let enable_approval_voting_parallel = (!config.chain_spec.is_kusama() && - !config.chain_spec.is_polkadot()) || - enable_approval_voting_parallel; + let enable_approval_voting_parallel = + !config.chain_spec.is_polkadot() || enable_approval_voting_parallel; let disable_grandpa = config.disable_grandpa; let name = config.network.node_name.clone(); @@ -1001,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, @@ -1020,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, })?; @@ -1042,7 +1034,7 @@ pub fn new_full< is_validator: role.is_authority(), enable_http_requests: false, custom_extensions: move |_| vec![], - }) + })? .run(client.clone(), task_manager.spawn_handle()) .boxed(), ); @@ -1391,8 +1383,6 @@ pub fn new_full< ); } - network_starter.start_network(); - Ok(NewFull { task_manager, client, @@ -1434,7 +1424,7 @@ pub fn new_chain_ops( } else if config.chain_spec.is_kusama() { chain_ops!(config, None) } else if config.chain_spec.is_westend() { - return chain_ops!(config, None) + return chain_ops!(config, None); } else { chain_ops!(config, None) } @@ -1486,7 +1476,7 @@ pub fn revert_backend( let revertible = blocks.min(best_number - finalized); if revertible == 0 { - return Ok(()) + return Ok(()); } let number = best_number - revertible; diff --git a/polkadot/node/service/src/parachains_db/upgrade.rs b/polkadot/node/service/src/parachains_db/upgrade.rs index 808acf04b4e7..52b010f0b5d0 100644 --- a/polkadot/node/service/src/parachains_db/upgrade.rs +++ b/polkadot/node/service/src/parachains_db/upgrade.rs @@ -463,7 +463,7 @@ mod tests { v3::migration_helpers::{v1_to_latest_sanity_check, v2_fill_test_data}, }; use polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter; - use polkadot_primitives_test_helpers::dummy_candidate_receipt; + use polkadot_primitives_test_helpers::dummy_candidate_receipt_v2; #[test] fn test_paritydb_migrate_0_to_1() { @@ -617,7 +617,7 @@ mod tests { assert_eq!(db.num_columns(), super::columns::v3::NUM_COLUMNS as u32); let db = DbAdapter::new(db, columns::v3::ORDERED_COL); // Fill the approval voting column with test data. - v1_fill_test_data(std::sync::Arc::new(db), approval_cfg, dummy_candidate_receipt) + v1_fill_test_data(std::sync::Arc::new(db), approval_cfg, dummy_candidate_receipt_v2) .unwrap() }; @@ -648,7 +648,7 @@ mod tests { assert_eq!(db.num_columns(), super::columns::v3::NUM_COLUMNS as u32); let db = DbAdapter::new(db, columns::v3::ORDERED_COL); // Fill the approval voting column with test data. - v2_fill_test_data(std::sync::Arc::new(db), approval_cfg, dummy_candidate_receipt) + v2_fill_test_data(std::sync::Arc::new(db), approval_cfg, dummy_candidate_receipt_v2) .unwrap() }; 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 293df9f6e6d5..8633818e775d 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -28,7 +28,7 @@ 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, 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 } diff --git a/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs index a3a475ac6b98..24cd734c6ae5 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs @@ -29,8 +29,8 @@ use polkadot_node_subsystem_types::messages::{ }; use polkadot_overseer::AllMessages; use polkadot_primitives::{ - BlockNumber, CandidateEvent, CandidateReceipt, CoreIndex, GroupIndex, Hash, Header, - Id as ParaId, Slot, ValidatorIndex, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt}, + BlockNumber, CoreIndex, GroupIndex, Hash, Header, Id as ParaId, Slot, ValidatorIndex, }; use polkadot_primitives_test_helpers::dummy_candidate_receipt_bad_sig; use rand::{seq::SliceRandom, SeedableRng}; @@ -189,7 +189,7 @@ pub fn make_header(parent_hash: Hash, slot: Slot, number: u32) -> Header { fn make_candidate(para_id: ParaId, hash: &Hash) -> CandidateReceipt { let mut r = dummy_candidate_receipt_bad_sig(*hash, Some(Default::default())); r.descriptor.para_id = para_id; - r + r.into() } /// Helper function to create a list of candidates that are included in the block diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index 807afb0438c9..79de6e72fc88 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -40,8 +40,8 @@ use polkadot_node_primitives::approval::{ v2::{CoreBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2}, }; use polkadot_primitives::{ - ApprovalVoteMultipleCandidates, CandidateEvent, CandidateHash, CandidateIndex, CoreIndex, Hash, - SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, + vstaging::CandidateEvent, ApprovalVoteMultipleCandidates, CandidateHash, CandidateIndex, + CoreIndex, Hash, SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, }; use rand::{seq::SliceRandom, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 29ebc4a419ae..1b20960a3f8a 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs @@ -66,8 +66,9 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers::mock::new_block_import_info; use polkadot_overseer::Handle as OverseerHandleReal; use polkadot_primitives::{ - BlockNumber, CandidateEvent, CandidateIndex, CandidateReceipt, Hash, Header, Slot, ValidatorId, - ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt}, + BlockNumber, CandidateIndex, Hash, Header, Slot, ValidatorId, ValidatorIndex, + ASSIGNMENT_KEY_TYPE_ID, }; use prometheus::Registry; use sc_keystore::LocalKeystore; diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index a99f013195fa..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, @@ -391,10 +389,10 @@ pub async fn benchmark_availability_write( candidate_hash: backed_candidate.hash(), n_validators: config.n_validators as u32, available_data, - expected_erasure_root: backed_candidate.descriptor().erasure_root, + 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 173b23f6b76e..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; @@ -34,8 +34,9 @@ use polkadot_node_subsystem_test_helpers::{ use polkadot_node_subsystem_util::availability_chunks::availability_chunk_indices; use polkadot_overseer::BlockInfo; use polkadot_primitives::{ - AvailabilityBitfield, BlockNumber, CandidateHash, CandidateReceipt, ChunkIndex, CoreIndex, - Hash, HeadData, Header, PersistedValidationData, Signed, SigningContext, ValidatorIndex, + vstaging::{CandidateReceiptV2 as CandidateReceipt, MutateDescriptorV2}, + AvailabilityBitfield, BlockNumber, CandidateHash, ChunkIndex, CoreIndex, Hash, HeadData, + Header, PersistedValidationData, Signed, SigningContext, ValidatorIndex, }; use polkadot_primitives_test_helpers::{dummy_candidate_receipt, dummy_hash}; use sp_core::H256; @@ -117,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), ) @@ -148,7 +149,10 @@ impl TestState { test_state.chunks.push(new_chunks); test_state.available_data.push(new_available_data); test_state.pov_size_to_candidate.insert(pov_size, index); - test_state.candidate_receipt_templates.push(candidate_receipt); + test_state.candidate_receipt_templates.push(CandidateReceipt { + descriptor: candidate_receipt.descriptor.into(), + commitments_hash: candidate_receipt.commitments_hash, + }); } test_state.block_infos = (1..=config.num_blocks) @@ -189,7 +193,9 @@ impl TestState { test_state.candidate_receipt_templates[candidate_index].clone(); // Make it unique. - candidate_receipt.descriptor.relay_parent = Hash::from_low_u64_be(index as u64); + candidate_receipt + .descriptor + .set_relay_parent(Hash::from_low_u64_be(index as u64)); // Store the new candidate in the state test_state.candidate_hashes.insert(candidate_receipt.hash(), candidate_index); 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 61523de1f1b5..69e838eb864e 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -26,13 +26,15 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::OverseerSignal; use polkadot_primitives::{ - node_features, ApprovalVotingParams, AsyncBackingParams, CandidateEvent, CandidateReceipt, - CoreState, GroupIndex, GroupRotationInfo, IndexedVec, NodeFeatures, OccupiedCore, - ScheduledCore, SessionIndex, SessionInfo, ValidationCode, ValidatorIndex, + node_features, + vstaging::{CandidateEvent, CandidateReceiptV2 as CandidateReceipt, CoreState, OccupiedCore}, + 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"; @@ -50,6 +52,8 @@ pub struct RuntimeApiState { babe_epoch: Option, // The session child index, session_index: SessionIndex, + // The claim queue + claim_queue: BTreeMap>, } #[derive(Clone)] @@ -79,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 { @@ -89,6 +111,7 @@ impl MockRuntimeApi { babe_epoch, session_index, node_features, + claim_queue, }, config, core_state, @@ -304,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) @@ -315,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 88b5e8b76b62..e9b586522d2b 100644 --- a/polkadot/node/subsystem-bench/src/lib/statement/test_state.rs +++ b/polkadot/node/subsystem-bench/src/lib/statement/test_state.rs @@ -41,12 +41,16 @@ use polkadot_node_subsystem_test_helpers::{ }; use polkadot_overseer::BlockInfo; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CompactStatement, - Hash, Header, Id, PersistedValidationData, SessionInfo, SignedStatement, SigningContext, - UncheckedSigned, ValidatorIndex, ValidatorPair, + vstaging::{ + CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, MutateDescriptorV2, + }, + BlockNumber, CandidateHash, CompactStatement, CoreIndex, Hash, Header, Id, + PersistedValidationData, SessionInfo, SignedStatement, SigningContext, UncheckedSigned, + ValidatorIndex, ValidatorPair, }; use polkadot_primitives_test_helpers::{ - dummy_committed_candidate_receipt, dummy_hash, dummy_head_data, dummy_pvd, + dummy_committed_candidate_receipt_v2, dummy_hash, dummy_head_data, dummy_pvd, }; use sc_network::{config::IncomingRequest, ProtocolName}; use sp_core::{Pair, H256}; @@ -58,6 +62,8 @@ use std::{ }, }; +const SESSION_INDEX: u32 = 0; + #[derive(Clone)] pub struct TestState { // Full test config @@ -125,8 +131,10 @@ impl TestState { let candidate_index = *pov_size_to_candidate.get(pov_size).expect("pov_size always exists; qed"); let mut receipt = receipt_templates[candidate_index].clone(); - receipt.descriptor.para_id = Id::new(core_idx as u32 + 1); - receipt.descriptor.relay_parent = block_info.hash; + 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 { @@ -190,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( @@ -240,7 +248,7 @@ fn generate_receipt_templates( pov_size_to_candidate .iter() .map(|(&pov_size, &index)| { - let mut receipt = dummy_committed_candidate_receipt(dummy_hash()); + let mut receipt = dummy_committed_candidate_receipt_v2(dummy_hash()); let (_, erasure_root) = derive_erasure_chunks_with_proofs_and_root( n_validators, &AvailableData { @@ -249,8 +257,8 @@ fn generate_receipt_templates( }, |_, _| {}, ); - receipt.descriptor.persisted_validation_data_hash = pvd.hash(); - receipt.descriptor.erasure_root = erasure_root; + receipt.descriptor.set_persisted_validation_data_hash(pvd.hash()); + receipt.descriptor.set_erasure_root(erasure_root); receipt }) .collect() @@ -317,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-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index a520e85f52a9..28a3a1ab82ab 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -42,14 +42,18 @@ use polkadot_node_primitives::{ ValidationResult, }; use polkadot_primitives::{ - async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BackedCandidate, - BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CandidateIndex, - CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, - ExecutorParams, GroupIndex, GroupRotationInfo, Hash, HeadData, Header as BlockHeader, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, - NodeFeatures, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, PvfExecKind, - SessionIndex, SessionInfo, SignedAvailabilityBitfield, SignedAvailabilityBitfields, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing, slashing, vstaging, + vstaging::{ + BackedCandidate, CandidateReceiptV2 as CandidateReceipt, + 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, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -182,6 +186,43 @@ 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. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PvfExecKind { + /// For dispute requests + Dispute, + /// For approval requests + Approval, + /// For backing requests from system parachains. With relay parent hash + BackingSystemParas(Hash), + /// For backing requests. With relay parent hash + Backing(Hash), +} + +impl PvfExecKind { + /// Converts priority level to &str + pub fn as_str(&self) -> &str { + match *self { + Self::Dispute => "dispute", + Self::Approval => "approval", + Self::BackingSystemParas(_) => "backing_system_paras", + Self::Backing(_) => "backing", + } + } +} + +impl From for RuntimePvfExecKind { + fn from(exec: PvfExecKind) -> Self { + match exec { + PvfExecKind::Dispute => RuntimePvfExecKind::Approval, + PvfExecKind::Approval => RuntimePvfExecKind::Approval, + PvfExecKind::BackingSystemParas(_) => RuntimePvfExecKind::Backing, + PvfExecKind::Backing(_) => RuntimePvfExecKind::Backing, + } + } +} + /// Messages received by the Collator Protocol subsystem. #[derive(Debug, derive_more::From)] pub enum CollatorProtocolMessage { @@ -667,7 +708,7 @@ pub enum RuntimeApiRequest { CandidatePendingAvailability(ParaId, RuntimeApiSender>), /// Get all events concerning candidates (backing, inclusion, time-out) in the parent of /// the block in whose state this request is executed. - CandidateEvents(RuntimeApiSender>), + CandidateEvents(RuntimeApiSender>), /// Get the execution environment parameter set by session index SessionExecutorParams(SessionIndex, RuntimeApiSender>), /// Get the session info for the given session, if stored. @@ -683,7 +724,7 @@ pub enum RuntimeApiRequest { /// Get information about the BABE epoch the block was included in. CurrentBabeEpoch(RuntimeApiSender), /// Get all disputes in relation to a relay parent. - FetchOnChainVotes(RuntimeApiSender>), + FetchOnChainVotes(RuntimeApiSender>), /// Submits a PVF pre-checking statement into the transaction pool. SubmitPvfCheckStatement(PvfCheckStatement, ValidatorSignature, RuntimeApiSender<()>), /// Returns code hashes of PVFs that require pre-checking by validators in the active set. @@ -718,7 +759,7 @@ pub enum RuntimeApiRequest { /// Returns all disabled validators at a given block height. DisabledValidators(RuntimeApiSender>), /// Get the backing state of the given para. - ParaBackingState(ParaId, RuntimeApiSender>), + ParaBackingState(ParaId, RuntimeApiSender>), /// Get candidate's acceptance limitations for asynchronous backing for a relay parent. /// /// If it's not supported by the Runtime, the async backing is said to be disabled. @@ -1215,7 +1256,7 @@ impl HypotheticalCandidate { /// Get the `ParaId` of the hypothetical candidate. pub fn candidate_para(&self) -> ParaId { match *self { - HypotheticalCandidate::Complete { ref receipt, .. } => receipt.descriptor().para_id, + HypotheticalCandidate::Complete { ref receipt, .. } => receipt.descriptor.para_id(), HypotheticalCandidate::Incomplete { candidate_para, .. } => candidate_para, } } @@ -1234,7 +1275,7 @@ impl HypotheticalCandidate { pub fn relay_parent(&self) -> Hash { match *self { HypotheticalCandidate::Complete { ref receipt, .. } => - receipt.descriptor().relay_parent, + receipt.descriptor.relay_parent(), HypotheticalCandidate::Incomplete { candidate_relay_parent, .. } => candidate_relay_parent, } @@ -1244,7 +1285,7 @@ impl HypotheticalCandidate { pub fn output_head_data_hash(&self) -> Option { match *self { HypotheticalCandidate::Complete { ref receipt, .. } => - Some(receipt.descriptor.para_head), + Some(receipt.descriptor.para_head()), HypotheticalCandidate::Incomplete { .. } => None, } } @@ -1267,10 +1308,10 @@ impl HypotheticalCandidate { } /// Get the validation code hash, if the candidate is complete. - pub fn validation_code_hash(&self) -> Option<&ValidationCodeHash> { + pub fn validation_code_hash(&self) -> Option { match *self { HypotheticalCandidate::Complete { ref receipt, .. } => - Some(&receipt.descriptor.validation_code_hash), + Some(receipt.descriptor.validation_code_hash()), HypotheticalCandidate::Incomplete { .. } => None, } } diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index a8af8b7996f9..4b96009f44bf 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -16,12 +16,18 @@ use async_trait::async_trait; use polkadot_primitives::{ - async_backing, runtime_api::ParachainHost, slashing, ApprovalVotingParams, Block, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, - CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id, - InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing, + runtime_api::ParachainHost, + slashing, vstaging, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + ApprovalVotingParams, Block, BlockNumber, CandidateCommitments, CandidateHash, CoreIndex, + DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id, InboundDownwardMessage, + InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, PersistedValidationData, + PvfCheckStatement, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, ValidatorSignature, }; use sc_client_api::{AuxStore, HeaderBackend}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; @@ -311,7 +317,7 @@ pub trait RuntimeApiSubsystemClient { &self, at: Hash, para_id: Id, - ) -> Result, ApiError>; + ) -> Result, ApiError>; // === v8 === @@ -380,10 +386,7 @@ where &self, at: Hash, ) -> Result>, ApiError> { - self.client - .runtime_api() - .availability_cores(at) - .map(|cores| cores.into_iter().map(|core| core.into()).collect::>()) + self.client.runtime_api().availability_cores(at) } async fn persisted_validation_data( @@ -436,10 +439,7 @@ where at: Hash, para_id: Id, ) -> Result>, ApiError> { - self.client - .runtime_api() - .candidate_pending_availability(at, para_id) - .map(|maybe_candidate| maybe_candidate.map(|candidate| candidate.into())) + self.client.runtime_api().candidate_pending_availability(at, para_id) } async fn candidates_pending_availability( @@ -447,19 +447,11 @@ where at: Hash, para_id: Id, ) -> Result>, ApiError> { - self.client - .runtime_api() - .candidates_pending_availability(at, para_id) - .map(|candidates| { - candidates.into_iter().map(|candidate| candidate.into()).collect::>() - }) + self.client.runtime_api().candidates_pending_availability(at, para_id) } async fn candidate_events(&self, at: Hash) -> Result>, ApiError> { - self.client - .runtime_api() - .candidate_events(at) - .map(|events| events.into_iter().map(|event| event.into()).collect::>()) + self.client.runtime_api().candidate_events(at) } async fn dmq_contents( @@ -490,10 +482,7 @@ where &self, at: Hash, ) -> Result>, ApiError> { - self.client - .runtime_api() - .on_chain_votes(at) - .map(|maybe_votes| maybe_votes.map(|votes| votes.into())) + self.client.runtime_api().on_chain_votes(at) } async fn session_executor_params( @@ -604,13 +593,8 @@ where &self, at: Hash, para_id: Id, - ) -> Result, ApiError> { - self.client - .runtime_api() - .para_backing_state(at, para_id) - .map(|maybe_backing_state| { - maybe_backing_state.map(|backing_state| backing_state.into()) - }) + ) -> Result, ApiError> { + self.client.runtime_api().para_backing_state(at, para_id) } async fn async_backing_params( diff --git a/polkadot/node/subsystem-util/src/backing_implicit_view.rs b/polkadot/node/subsystem-util/src/backing_implicit_view.rs index a805ef8165e5..6f2191e7add2 100644 --- a/polkadot/node/subsystem-util/src/backing_implicit_view.rs +++ b/polkadot/node/subsystem-util/src/backing_implicit_view.rs @@ -20,14 +20,14 @@ 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 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}, }; // Always aim to retain 1 block before the active leaves. @@ -396,13 +396,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 +411,7 @@ where sender .send_message(ChainApiMessage::Ancestors { hash: leaf_hash, - k: allowed_ancestry_len, + k: allowed_ancestry_len as usize, response_channel: tx, }) .await; diff --git a/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs b/polkadot/node/subsystem-util/src/inclusion_emulator/mod.rs index 0c3b40743495..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(), @@ -770,7 +777,7 @@ pub trait HypotheticalOrConcreteCandidate { /// Return a reference to the persisted validation data, if present. fn persisted_validation_data(&self) -> Option<&PersistedValidationData>; /// Return a reference to the validation code hash, if present. - fn validation_code_hash(&self) -> Option<&ValidationCodeHash>; + fn validation_code_hash(&self) -> Option; /// Return the parent head hash. fn parent_head_data_hash(&self) -> Hash; /// Return the output head hash, if present. @@ -790,7 +797,7 @@ impl HypotheticalOrConcreteCandidate for HypotheticalCandidate { self.persisted_validation_data() } - fn validation_code_hash(&self) -> Option<&ValidationCodeHash> { + fn validation_code_hash(&self) -> Option { self.validation_code_hash() } @@ -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-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index 4bab4e80fe50..3bed18558941 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -41,12 +41,15 @@ use codec::Encode; use futures::channel::{mpsc, oneshot}; use polkadot_primitives::{ - async_backing::BackingState, slashing, AsyncBackingParams, AuthorityDiscoveryId, - CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, EncodeAs, - ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, - SigningContext, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + slashing, + vstaging::{ + async_backing::BackingState, CandidateEvent, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, ScrapedOnChainVotes, + }, + AsyncBackingParams, AuthorityDiscoveryId, CandidateHash, CoreIndex, EncodeAs, ExecutorParams, + GroupIndex, GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption, + PersistedValidationData, SessionIndex, SessionInfo, Signed, SigningContext, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; pub use rand; use runtime::get_disabled_validators_with_fallback; diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index 2f9d3ed7b4f4..d84951ae1366 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -30,11 +30,13 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ - node_features::FeatureIndex, slashing, AsyncBackingParams, CandidateEvent, CandidateHash, - CoreIndex, CoreState, EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, - Id as ParaId, IndexedVec, NodeFeatures, OccupiedCore, ScrapedOnChainVotes, SessionIndex, - SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + node_features::FeatureIndex, + slashing, + vstaging::{CandidateEvent, CoreState, OccupiedCore, ScrapedOnChainVotes}, + AsyncBackingParams, CandidateHash, CoreIndex, EncodeAs, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, SessionIndex, SessionInfo, + Signed, SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; use std::collections::{BTreeMap, VecDeque}; diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 8eb6105f98e2..4ef9d88621fb 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -71,6 +71,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", diff --git a/polkadot/node/test/service/src/chain_spec.rs b/polkadot/node/test/service/src/chain_spec.rs index 00d62af0b273..ae4e84b7725e 100644 --- a/polkadot/node/test/service/src/chain_spec.rs +++ b/polkadot/node/test/service/src/chain_spec.rs @@ -21,13 +21,13 @@ use polkadot_primitives::{ AccountId, AssignmentId, SchedulerParams, ValidatorId, MAX_CODE_SIZE, MAX_POV_SIZE, }; use polkadot_service::chain_spec::Extensions; -pub use polkadot_service::chain_spec::{get_account_id_from_seed, get_from_seed}; use polkadot_test_runtime::BABE_GENESIS_EPOCH_CONFIG; use sc_chain_spec::{ChainSpec, ChainType}; use sc_consensus_grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; -use sp_core::sr25519; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; +use sp_keyring::Sr25519Keyring; use sp_runtime::Perbill; use test_runtime_constants::currency::DOTS; @@ -65,7 +65,7 @@ pub fn polkadot_local_testnet_config() -> PolkadotChainSpec { pub fn polkadot_local_testnet_genesis() -> serde_json::Value { polkadot_testnet_genesis( vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -75,31 +75,18 @@ fn get_authority_keys_from_seed( seed: &str, ) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } fn testnet_accounts() -> Vec { - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ] + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect() } /// Helper function to create polkadot `RuntimeGenesisConfig` for testing diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index aa7295dddc5d..6e09bb9e4310 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -32,7 +32,7 @@ use polkadot_service::{ Error, FullClient, IsParachainNode, NewFull, OverseerGen, PrometheusConfig, }; use polkadot_test_runtime::{ - ParasCall, ParasSudoWrapperCall, Runtime, SignedExtra, SignedPayload, SudoCall, + ParasCall, ParasSudoWrapperCall, Runtime, SignedPayload, SudoCall, TxExtension, UncheckedExtrinsic, VERSION, }; @@ -414,7 +414,7 @@ pub fn construct_extrinsic( let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -423,10 +423,11 @@ pub fn construct_extrinsic( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ); + ) + .into(); let raw_payload = SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ( (), VERSION.spec_version, @@ -443,7 +444,7 @@ pub fn construct_extrinsic( function.clone(), polkadot_test_runtime::Address::Id(caller.public().into()), polkadot_primitives::Signature::Sr25519(signature), - extra.clone(), + tx_ext.clone(), ) } diff --git a/polkadot/parachain/test-parachains/adder/collator/src/lib.rs b/polkadot/parachain/test-parachains/adder/collator/src/lib.rs index daeb8bc915dd..a2fb623331a0 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/lib.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/lib.rs @@ -236,7 +236,7 @@ impl Collator { if let Ok(res) = recv.await { if !matches!( res.statement.payload(), - Statement::Seconded(s) if s.descriptor.pov_hash == compressed_pov.hash(), + Statement::Seconded(s) if s.descriptor.pov_hash() == compressed_pov.hash(), ) { log::error!( "Seconded statement should match our collation: {:?}", diff --git a/polkadot/parachain/test-parachains/undying/collator/src/lib.rs b/polkadot/parachain/test-parachains/undying/collator/src/lib.rs index 920099f4499d..448c181ae062 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/lib.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/lib.rs @@ -282,7 +282,7 @@ impl Collator { if let Ok(res) = recv.await { if !matches!( res.statement.payload(), - Statement::Seconded(s) if s.descriptor.pov_hash == compressed_pov.hash(), + Statement::Seconded(s) if s.descriptor.pov_hash() == compressed_pov.hash(), ) { log::error!( "Seconded statement should match our collation: {:?}", diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index a8cd6cb5f4e0..dd269caa2d60 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -16,6 +16,7 @@ codec = { features = ["bit-vec", "derive"], workspace = true } scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } log = { workspace = true } serde = { features = ["alloc", "derive"], workspace = true } +thiserror = { workspace = true, optional = true } sp-application-crypto = { features = ["serde"], workspace = true } sp-inherents = { workspace = true } @@ -59,6 +60,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "sp-std/std", + "thiserror", ] runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", diff --git a/polkadot/primitives/src/v8/mod.rs b/polkadot/primitives/src/v8/mod.rs index a51ee0bd99bf..fdcb9fe8fb7e 100644 --- a/polkadot/primitives/src/v8/mod.rs +++ b/polkadot/primitives/src/v8/mod.rs @@ -484,7 +484,7 @@ pub fn collator_signature_payload>( payload } -fn check_collator_signature>( +pub(crate) fn check_collator_signature>( relay_parent: &H, para_id: &Id, persisted_validation_data_hash: &Hash, @@ -2093,7 +2093,9 @@ pub struct SchedulerParams { pub lookahead: u32, /// How many cores are managed by the coretime chain. pub num_cores: u32, - /// The max number of times a claim can time out in availability. + /// Deprecated and no longer used by the runtime. + /// Removal is tracked by . + #[deprecated] pub max_availability_timeouts: u32, /// The maximum queue size of the pay as you go module. pub on_demand_queue_max_size: u32, @@ -2104,13 +2106,14 @@ pub struct SchedulerParams { pub on_demand_fee_variability: Perbill, /// The minimum amount needed to claim a slot in the spot pricing queue. pub on_demand_base_fee: Balance, - /// The number of blocks a claim stays in the scheduler's claim queue before getting cleared. - /// This number should go reasonably higher than the number of blocks in the async backing - /// lookahead. + /// Deprecated and no longer used by the runtime. + /// Removal is tracked by . + #[deprecated] pub ttl: BlockNumber, } impl> Default for SchedulerParams { + #[allow(deprecated)] fn default() -> Self { Self { group_rotation_frequency: 1u32.into(), diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index bc687f7e2fbe..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))] @@ -107,14 +111,42 @@ impl From> for CandidateDescriptor { } } -#[cfg(any(feature = "runtime-benchmarks", feature = "test"))] -impl From> for CandidateDescriptorV2 { +fn clone_into_array(slice: &[T]) -> A +where + A: Default + AsMut<[T]>, + T: Clone, +{ + let mut a = A::default(); + >::as_mut(&mut a).clone_from_slice(slice); + a +} + +impl From> for CandidateDescriptorV2 { fn from(value: CandidateDescriptor) -> Self { - Decode::decode(&mut value.encode().as_slice()).unwrap() + let collator = value.collator.as_slice(); + + Self { + para_id: value.para_id, + relay_parent: value.relay_parent, + // Use first byte of the `collator` field. + version: InternalVersion(collator[0]), + // Use next 2 bytes of the `collator` field. + core_index: u16::from_ne_bytes(clone_into_array(&collator[1..=2])), + // Use next 4 bytes of the `collator` field. + session_index: SessionIndex::from_ne_bytes(clone_into_array(&collator[3..=6])), + // Use remaing 25 bytes of the `collator` field. + reserved1: clone_into_array(&collator[7..]), + persisted_validation_data_hash: value.persisted_validation_data_hash, + pov_hash: value.pov_hash, + erasure_root: value.erasure_root, + reserved2: value.signature.into_inner().0, + para_head: value.para_head, + validation_code_hash: value.validation_code_hash, + } } } -impl CandidateDescriptorV2 { +impl> CandidateDescriptorV2 { /// Constructor pub fn new( para_id: Id, @@ -143,17 +175,92 @@ impl CandidateDescriptorV2 { } } - /// Set the PoV size in the descriptor. Only for tests. - #[cfg(feature = "test")] - pub fn set_pov_hash(&mut self, pov_hash: Hash) { + /// Check the signature of the collator within this descriptor. + pub fn check_collator_signature(&self) -> Result<(), ()> { + // Return `Ok` if collator signature is not included (v2+ descriptor). + let Some(collator) = self.collator() else { return Ok(()) }; + + let Some(signature) = self.signature() else { return Ok(()) }; + + super::v8::check_collator_signature( + &self.relay_parent, + &self.para_id, + &self.persisted_validation_data_hash, + &self.pov_hash, + &self.validation_code_hash, + &collator, + &signature, + ) + } +} + +/// A trait to allow changing the descriptor field values in tests. +#[cfg(feature = "test")] + +pub trait MutateDescriptorV2 { + /// Set the relay parent of the descriptor. + fn set_relay_parent(&mut self, relay_parent: H); + /// Set the `ParaId` of the descriptor. + fn set_para_id(&mut self, para_id: Id); + /// Set the PoV hash of the descriptor. + fn set_pov_hash(&mut self, pov_hash: Hash); + /// Set the version field of the descriptor. + 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. + fn set_para_head(&mut self, para_head: Hash); + /// Set the core index of the descriptor. + fn set_core_index(&mut self, core_index: CoreIndex); + /// Set the session index of the descriptor. + fn set_session_index(&mut self, session_index: SessionIndex); +} + +#[cfg(feature = "test")] +impl MutateDescriptorV2 for CandidateDescriptorV2 { + fn set_para_id(&mut self, para_id: Id) { + self.para_id = para_id; + } + + fn set_relay_parent(&mut self, relay_parent: H) { + self.relay_parent = relay_parent; + } + + fn set_pov_hash(&mut self, pov_hash: Hash) { self.pov_hash = pov_hash; } - /// Set the version in the descriptor. Only for tests. - #[cfg(feature = "test")] - pub fn set_version(&mut self, version: InternalVersion) { + fn set_version(&mut self, version: InternalVersion) { self.version = version; } + + fn set_core_index(&mut self, core_index: CoreIndex) { + self.core_index = core_index.0 as u16; + } + + fn set_session_index(&mut self, session_index: SessionIndex) { + self.session_index = session_index; + } + + fn set_persisted_validation_data_hash(&mut self, persisted_validation_data_hash: Hash) { + 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; + } + + fn set_para_head(&mut self, para_head: Hash) { + self.para_head = para_head; + } } /// A candidate-receipt at version 2. @@ -233,6 +340,24 @@ impl CandidateReceiptV2 { } } +impl From> for CandidateReceiptV2 { + fn from(value: super::v8::CandidateReceipt) -> Self { + CandidateReceiptV2 { + descriptor: value.descriptor.into(), + commitments_hash: value.commitments_hash, + } + } +} + +impl From> for CommittedCandidateReceiptV2 { + fn from(value: super::v8::CommittedCandidateReceipt) -> Self { + CommittedCandidateReceiptV2 { + descriptor: value.descriptor.into(), + commitments: value.commitments, + } + } +} + impl CommittedCandidateReceiptV2 { /// Transforms this into a plain `CandidateReceipt`. pub fn to_plain(&self) -> CandidateReceiptV2 { @@ -309,66 +434,82 @@ 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)] -pub enum CandidateReceiptError { +#[cfg_attr(feature = "std", derive(thiserror::Error))] +pub enum CommittedCandidateReceiptError { /// The specified core index is invalid. + #[cfg_attr(feature = "std", error("The specified core index is invalid"))] InvalidCoreIndex, /// The core index in commitments doesn't match the one in descriptor + #[cfg_attr( + feature = "std", + error("The core index in commitments doesn't match the one in descriptor") + )] CoreIndexMismatch, /// 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", + error("The parachain is not assigned to any core at specified claim queue offset") + )] NoAssignment, /// No core was selected. The `SelectCore` commitment is mandatory for /// v2 receipts if parachains has multiple cores assigned. + #[cfg_attr(feature = "std", error("Core selector not present"))] NoCoreSelected, /// 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 { ($field:ident, $type:ident) => { - /// Returns the value of $field field. + /// Returns the value of `$field` field. pub fn $field(&self) -> $type { self.$field } @@ -456,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(()) @@ -703,6 +850,13 @@ pub struct OccupiedCore { pub candidate_descriptor: CandidateDescriptorV2, } +impl OccupiedCore { + /// Get the Para currently occupying this core. + pub fn para_id(&self) -> Id { + self.candidate_descriptor.para_id + } +} + /// The state of a particular availability core. #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(PartialEq))] @@ -724,6 +878,28 @@ pub enum CoreState { Free, } +impl CoreState { + /// Returns the scheduled `ParaId` for the core or `None` if nothing is scheduled. + /// + /// This function is deprecated. `ClaimQueue` should be used to obtain the scheduled `ParaId`s + /// for each core. + #[deprecated( + note = "`para_id` will be removed. Use `ClaimQueue` to query the scheduled `para_id` instead." + )] + pub fn para_id(&self) -> Option { + match self { + Self::Occupied(ref core) => core.next_up_on_available.as_ref().map(|n| n.para_id), + Self::Scheduled(core) => Some(core.para_id), + Self::Free => None, + } + } + + /// Is this core state `Self::Occupied`? + pub fn is_occupied(&self) -> bool { + matches!(self, Self::Occupied(_)) + } +} + impl From> for super::v8::OccupiedCore { fn from(value: OccupiedCore) -> Self { Self { @@ -841,6 +1017,25 @@ mod tests { assert_eq!(old_ccr.hash(), new_ccr.hash()); } + #[test] + fn test_from_v1_descriptor() { + let mut old_ccr = dummy_old_committed_candidate_receipt().to_plain(); + old_ccr.descriptor.collator = dummy_collator_id(); + old_ccr.descriptor.signature = dummy_collator_signature(); + + let mut new_ccr = dummy_committed_candidate_receipt_v2().to_plain(); + + // Override descriptor from old candidate receipt. + new_ccr.descriptor = old_ccr.descriptor.clone().into(); + + // We get same candidate hash. + assert_eq!(old_ccr.hash(), new_ccr.hash()); + + assert_eq!(new_ccr.descriptor.version(), CandidateDescriptorVersion::V1); + assert_eq!(old_ccr.descriptor.collator, new_ccr.descriptor.collator().unwrap()); + assert_eq!(old_ccr.descriptor.signature, new_ccr.descriptor.signature().unwrap()); + } + #[test] fn invalid_version_descriptor() { let mut new_ccr = dummy_committed_candidate_receipt_v2(); @@ -855,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))) ) } @@ -893,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(); @@ -907,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( @@ -918,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] @@ -1009,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()); @@ -1017,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); } @@ -1046,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..27de3c4b9c56 100644 --- a/polkadot/primitives/test-helpers/Cargo.toml +++ b/polkadot/primitives/test-helpers/Cargo.toml @@ -14,5 +14,5 @@ sp-keyring = { 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 } +polkadot-primitives = { features = ["test"], workspace = true, default-features = true } rand = { workspace = true, default-features = true } diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index b0f78717dd97..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; @@ -44,7 +46,7 @@ pub fn dummy_candidate_receipt>(relay_parent: H) -> CandidateRece } /// Creates a v2 candidate receipt with filler data. -pub fn dummy_candidate_receipt_v2>(relay_parent: H) -> CandidateReceiptV2 { +pub fn dummy_candidate_receipt_v2 + Copy>(relay_parent: H) -> CandidateReceiptV2 { CandidateReceiptV2:: { commitments_hash: dummy_candidate_commitments(dummy_head_data()).hash(), descriptor: dummy_candidate_descriptor_v2(relay_parent), @@ -62,7 +64,7 @@ pub fn dummy_committed_candidate_receipt>( } /// Creates a v2 committed candidate receipt with filler data. -pub fn dummy_committed_candidate_receipt_v2>( +pub fn dummy_committed_candidate_receipt_v2 + Copy>( relay_parent: H, ) -> CommittedCandidateReceiptV2 { CommittedCandidateReceiptV2 { @@ -88,6 +90,23 @@ pub fn dummy_candidate_receipt_bad_sig( } } +/// Create a candidate receipt with a bogus signature and filler data. Optionally set the commitment +/// hash with the `commitments` arg. +pub fn dummy_candidate_receipt_v2_bad_sig( + relay_parent: Hash, + commitments: impl Into>, +) -> CandidateReceiptV2 { + let commitments_hash = if let Some(commitments) = commitments.into() { + commitments + } else { + dummy_candidate_commitments(dummy_head_data()).hash() + }; + CandidateReceiptV2:: { + commitments_hash, + descriptor: dummy_candidate_descriptor_bad_sig(relay_parent).into(), + } +} + /// Create candidate commitments with filler data. pub fn dummy_candidate_commitments(head_data: impl Into>) -> CandidateCommitments { CandidateCommitments { @@ -144,7 +163,9 @@ pub fn dummy_candidate_descriptor>(relay_parent: H) -> CandidateD } /// Create a v2 candidate descriptor with filler data. -pub fn dummy_candidate_descriptor_v2>(relay_parent: H) -> CandidateDescriptorV2 { +pub fn dummy_candidate_descriptor_v2 + Copy>( + relay_parent: H, +) -> CandidateDescriptorV2 { let invalid = Hash::zero(); let descriptor = make_valid_candidate_descriptor_v2( 1.into(), @@ -180,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()) } @@ -208,7 +236,7 @@ pub fn make_candidate( parent_head: HeadData, head_data: HeadData, validation_code_hash: ValidationCodeHash, -) -> (CommittedCandidateReceipt, PersistedValidationData) { +) -> (CommittedCandidateReceiptV2, PersistedValidationData) { let pvd = dummy_pvd(parent_head, relay_parent_number); let commitments = CandidateCommitments { head_data, @@ -225,7 +253,36 @@ pub fn make_candidate( candidate.descriptor.para_id = para_id; candidate.descriptor.persisted_validation_data_hash = pvd.hash(); candidate.descriptor.validation_code_hash = validation_code_hash; - let candidate = CommittedCandidateReceipt { descriptor: candidate.descriptor, commitments }; + let candidate = + CommittedCandidateReceiptV2 { descriptor: candidate.descriptor.into(), commitments }; + + (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) } @@ -269,7 +326,7 @@ pub fn make_valid_candidate_descriptor>( } /// Create a v2 candidate descriptor. -pub fn make_valid_candidate_descriptor_v2>( +pub fn make_valid_candidate_descriptor_v2 + Copy>( para_id: ParaId, relay_parent: H, core_index: CoreIndex, @@ -335,11 +392,11 @@ impl std::default::Default for TestCandidateBuilder { impl TestCandidateBuilder { /// Build a `CandidateReceipt`. - pub fn build(self) -> CandidateReceipt { + pub fn build(self) -> CandidateReceiptV2 { let mut descriptor = dummy_candidate_descriptor(self.relay_parent); descriptor.para_id = self.para_id; descriptor.pov_hash = self.pov_hash; - CandidateReceipt { descriptor, commitments_hash: self.commitments_hash } + CandidateReceipt { descriptor, commitments_hash: self.commitments_hash }.into() } } 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..85415e42a11c 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -697,14 +697,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 +706,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/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index cda6f3240dd2..01b56b31cf20 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -27,6 +27,7 @@ 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 } pallet-authorship = { workspace = true } @@ -130,6 +131,7 @@ runtime-benchmarks = [ "pallet-identity/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index 96c98c45954d..65942c127b1c 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -665,12 +665,21 @@ mod tests { } ); - impl frame_system::offchain::SendTransactionTypes for Test + impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + 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) + } } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 32686d1a0bfa..1ee80dd76e2d 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -19,7 +19,7 @@ #[cfg(not(feature = "std"))] use alloc::{format, string::String}; use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use core::fmt::Debug; use frame_support::{ ensure, @@ -33,9 +33,14 @@ use scale_info::TypeInfo; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; use sp_runtime::{ - traits::{CheckedSub, DispatchInfoOf, SignedExtension, Zero}, + impl_tx_ext_default, + traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, CheckedSub, DispatchInfoOf, + Dispatchable, TransactionExtension, Zero, + }, transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError, + ValidTransaction, }, RuntimeDebug, }; @@ -51,6 +56,7 @@ pub trait WeightInfo { fn claim_attest() -> Weight; fn attest() -> Weight; fn move_claim() -> Weight; + fn prevalidate_attests() -> Weight; } pub struct TestWeightInfo; @@ -70,11 +76,24 @@ impl WeightInfo for TestWeightInfo { 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, + Encode, + Decode, + Clone, + Copy, + Eq, + PartialEq, + RuntimeDebug, + TypeInfo, + Serialize, + Deserialize, + MaxEncodedLen, )] pub enum StatementKind { /// Statement required to be made by non-SAFT holders. @@ -108,7 +127,9 @@ impl Default for StatementKind { /// 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)] +#[derive( + Clone, Copy, PartialEq, Eq, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen, +)] pub struct EthereumAddress([u8; 20]); impl Serialize for EthereumAddress { @@ -142,7 +163,7 @@ impl<'de> Deserialize<'de> for EthereumAddress { } } -#[derive(Encode, Decode, Clone, TypeInfo)] +#[derive(Encode, Decode, Clone, TypeInfo, MaxEncodedLen)] pub struct EcdsaSignature(pub [u8; 65]); impl PartialEq for EcdsaSignature { @@ -164,7 +185,6 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::pallet] - #[pallet::without_storage_info] pub struct Pallet(_); /// Configuration trait. @@ -400,7 +420,7 @@ pub mod pallet { /// Attest to a statement, needed to finalize the claims process. /// /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a - /// `SignedExtension`. + /// `TransactionExtension`. /// /// Unsigned Validation: /// A call to attest is deemed valid if the sender has a `Preclaim` registered @@ -611,58 +631,57 @@ impl PrevalidateAttests where ::RuntimeCall: IsSubType>, { - /// Create new `SignedExtension` to check runtime version. + /// Create new `TransactionExtension` to check runtime version. pub fn new() -> Self { Self(core::marker::PhantomData) } } -impl SignedExtension for PrevalidateAttests +impl TransactionExtension for PrevalidateAttests where ::RuntimeCall: IsSubType>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); const IDENTIFIER: &'static str = "PrevalidateAttests"; + type Implicit = (); + type Pre = (); + type Val = (); - fn additional_signed(&self) -> Result { - Ok(()) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + fn weight(&self, call: &T::RuntimeCall) -> Weight { + if let Some(Call::attest { .. }) = call.is_sub_type() { + T::WeightInfo::prevalidate_attests() + } else { + Weight::zero() + } } - // - // The weight of this logic is included in the `attest` dispatchable. - // fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { - if let Some(local_call) = call.is_sub_type() { - if let Call::attest { statement: attested_statement } = local_call { - 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); - } + _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()) + Ok((ValidTransaction::default(), (), origin)) } + + impl_tx_ext_default!(T::RuntimeCall; prepare); } #[cfg(any(test, feature = "runtime-benchmarks"))] @@ -699,6 +718,7 @@ mod tests { use super::*; 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 @@ -713,8 +733,11 @@ mod tests { }; use pallet_balances; use sp_runtime::{ - traits::Identity, transaction_validity::TransactionLongevity, BuildStorage, - DispatchError::BadOrigin, TokenError, + traits::{DispatchTransaction, Identity}, + transaction_validity::TransactionLongevity, + BuildStorage, + DispatchError::BadOrigin, + TokenError, }; type Block = frame_system::mocking::MockBlock; @@ -1055,8 +1078,8 @@ mod tests { }); let di = c.get_dispatch_info(); assert_eq!(di.pays_fee, Pays::No); - let r = p.validate(&42, &c, &di, 20); - assert_eq!(r, TransactionValidity::Ok(ValidTransaction::default())); + let r = p.validate_only(Some(42).into(), &c, &di, 20, External, 0); + assert_eq!(r.unwrap().0, ValidTransaction::default()); }); } @@ -1068,13 +1091,13 @@ mod tests { statement: StatementKind::Regular.to_text().to_vec(), }); let di = c.get_dispatch_info(); - let r = p.validate(&42, &c, &di, 20); + let r = p.validate_only(Some(42).into(), &c, &di, 20, External, 0); 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(&69, &c, &di, 20); + let r = p.validate_only(Some(69).into(), &c, &di, 20, External, 0); assert!(r.is_err()); }); } @@ -1431,11 +1454,17 @@ mod tests { mod benchmarking { use super::*; use crate::claims::Call; - use frame_benchmarking::{account, benchmarks}; - use frame_support::traits::UnfilteredDispatchable; + use frame_benchmarking::v2::*; + use frame_support::{ + dispatch::{DispatchInfo, GetDispatchInfo}, + traits::UnfilteredDispatchable, + }; use frame_system::RawOrigin; use secp_utils::*; - use sp_runtime::{traits::ValidateUnsigned, DispatchResult}; + use sp_runtime::{ + traits::{DispatchTransaction, ValidateUnsigned}, + DispatchResult, + }; const SEED: u32 = 0; @@ -1470,145 +1499,168 @@ mod benchmarking { Ok(()) } - benchmarks! { + #[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. - claim { + #[benchmark] + fn claim() -> Result<(), BenchmarkError> { let c = MAX_CLAIMS; - - for i in 0 .. c / 2 { + 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)?; + 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(); - }: { - 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())?; - } - verify { + 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. - mint_claim { + #[benchmark] + fn mint_claim() -> Result<(), BenchmarkError> { let c = MAX_CLAIMS; - - for i in 0 .. c / 2 { + 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; - }: _(RawOrigin::Root, eth_address, VALUE.into(), vesting, Some(statement)) - verify { + + #[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. - claim_attest { + #[benchmark] + fn claim_attest() -> Result<(), BenchmarkError> { let c = MAX_CLAIMS; - - for i in 0 .. c / 2 { + 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 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))?; + 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(); + statement: StatementKind::Regular.to_text().to_vec(), + } + .encode(); let source = sp_runtime::transaction_validity::TransactionSource::External; - }: { - 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())?; - } - verify { + + #[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. - attest { + #[benchmark] + fn attest() -> Result<(), BenchmarkError> { let c = MAX_CLAIMS; - - for i in 0 .. c / 2 { + 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 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))?; + 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 call = super::Call::::attest { statement: StatementKind::Regular.to_text().to_vec() }; - // We have to copy the validate statement here because of trait issues... :( - let validate = |who: &T::AccountId, call: &super::Call| -> DispatchResult { - if let Call::attest{ statement: attested_statement } = call { - let signer = Preclaims::::get(who).ok_or("signer has no claim")?; - if let Some(s) = Signing::::get(signer) { - ensure!(&attested_statement[..] == s.to_text(), "invalid statement"); - } - } - Ok(()) - }; - let call_enc = call.encode(); - }: { - let call = as Decode>::decode(&mut &*call_enc) - .expect("call is encoded above, encoding must be correct"); - validate(&account, &call)?; - call.dispatch_bypass_filter(RawOrigin::Signed(account).into())?; - } - verify { + let stmt = StatementKind::Regular.to_text().to_vec(); + + #[extrinsic_call] + _(RawOrigin::Signed(account), stmt); + assert_eq!(Claims::::get(eth_address), None); + Ok(()) } - move_claim { + #[benchmark] + fn move_claim() -> Result<(), BenchmarkError> { let c = MAX_CLAIMS; - - for i in 0 .. c / 2 { + 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 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_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); @@ -1616,37 +1668,85 @@ mod benchmarking { assert!(Claims::::contains_key(eth_address)); assert!(!Claims::::contains_key(new_eth_address)); - }: _(RawOrigin::Root, eth_address, new_eth_address, Some(account)) - verify { + + #[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 - #[extra] - keccak256 { - let i in 0 .. 10_000; + #[benchmark(extra)] + fn keccak256(i: Linear<0, 10_000>) { let bytes = (i).encode(); - }: { - for index in 0 .. i { - let _hash = keccak_256(&bytes); + + #[block] + { + for _ in 0..i { + let _hash = keccak_256(&bytes); + } } } // Benchmark the time it takes to do `repeat` number of `eth_recover` - #[extra] - eth_recover { - let i in 0 .. 1_000; + #[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(); - }: { - for _ in 0 .. i { - assert!(super::Pallet::::eth_recover(&signature, &data, extra).is_some()); + + #[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!( diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index b6a93cf53685..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 }])) } } } @@ -366,6 +387,7 @@ mod tests { type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = ConstU64<0>; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 7a689a517eaa..8a76a138305e 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -98,12 +98,21 @@ frame_support::construct_runtime!( } ); -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + 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) + } } use crate::{auctions::Error as AuctionsError, crowdloan::Error as CrowdloanError}; @@ -279,6 +288,7 @@ impl pallet_identity::Config for Test { type Slashed = (); type BasicDeposit = ConstU32<100>; type ByteDeposit = ConstU32<10>; + type UsernameDeposit = ConstU32<10>; type SubAccountDeposit = ConstU32<100>; type MaxSubAccounts = ConstU32<2>; type IdentityInformation = IdentityInfo>; @@ -289,6 +299,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<100>; + type UsernameGracePeriod = ConstU32<10>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 07f02e926561..2ead621dedf0 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -752,12 +752,21 @@ mod tests { } ); - impl frame_system::offchain::SendTransactionTypes for Test + impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + 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); diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 9cbb907536d9..cec92540654c 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -479,7 +479,8 @@ where mod tests { use super::*; - use sp_core::{crypto::AccountId32, ed25519, Pair, Public, H256}; + 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; @@ -488,10 +489,9 @@ mod tests { traits::{Currency, WithdrawReasons}, }; use sp_runtime::{ - traits::{BlakeTwo256, Dispatchable, IdentifyAccount, Identity, IdentityLookup, Verify}, + traits::{BlakeTwo256, Dispatchable, Identity, IdentityLookup}, ArithmeticError, BuildStorage, DispatchError::BadOrigin, - MultiSignature, }; type Block = frame_system::mocking::MockBlock; @@ -602,33 +602,16 @@ mod tests { Balances::make_free_balance_be(&payment_account(), 100_000); } - type AccountPublic = ::Signer; - - /// Helper function to generate a crypto pair from seed - fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() - } - - /// Helper function to generate an account ID from seed - fn get_account_id_from_seed(seed: &str) -> AccountId - where - AccountPublic: From<::Public>, - { - AccountPublic::from(get_from_seed::(seed)).into_account() - } - fn alice() -> AccountId { - get_account_id_from_seed::("Alice") + Sr25519Keyring::Alice.to_account_id() } fn alice_ed25519() -> AccountId { - get_account_id_from_seed::("Alice") + Ed25519Keyring::Alice.to_account_id() } fn bob() -> AccountId { - get_account_id_from_seed::("Bob") + Sr25519Keyring::Bob.to_account_id() } fn alice_signature() -> [u8; 64] { diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index 37fe7f0b59e9..7ff7f69faf14 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -157,7 +157,7 @@ impl InspectMessageQueues for ChildParachainRouter { 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, } } @@ -318,9 +310,12 @@ impl AssignmentProvider> for Pallet { Assignment::Bulk(para_id) } - fn session_core_count() -> u32 { - let config = configuration::ActiveConfig::::get(); - config.scheduler_params.num_cores + fn assignment_duplicated(assignment: &Assignment) { + match assignment { + Assignment::Pool { para_id, core_index } => + on_demand::Pallet::::assignment_duplicated(*para_id, *core_index), + Assignment::Bulk(_) => {}, + } } } @@ -384,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 e7994b8ef820..ab011bfc4ae1 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs @@ -26,7 +26,6 @@ use crate::{ paras::{ParaGenesisArgs, ParaKind}, scheduler::common::Assignment, }; -use alloc::collections::btree_map::BTreeMap; use frame_support::{assert_noop, assert_ok, pallet_prelude::*, traits::Currency}; use pallet_broker::TaskId; use polkadot_primitives::{BlockNumber, Id as ParaId, SessionIndex, ValidationCode}; @@ -78,7 +77,7 @@ fn run_to_block( OnDemand::on_initialize(b + 1); // In the real runtime this is expected to be called by the `InclusionInherent` pallet. - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); + Scheduler::advance_claim_queue(&Default::default()); } } @@ -236,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(|| { @@ -256,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, )); @@ -282,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 @@ -320,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 - ); }); } @@ -375,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( @@ -409,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/assigner_parachains.rs b/polkadot/runtime/parachains/src/assigner_parachains.rs deleted file mode 100644 index 3c735b999cf2..000000000000 --- a/polkadot/runtime/parachains/src/assigner_parachains.rs +++ /dev/null @@ -1,69 +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 . - -//! The bulk (parachain slot auction) blockspace assignment provider. -//! This provider is tightly coupled with the configuration and paras modules. - -#[cfg(test)] -mod mock_helpers; -#[cfg(test)] -mod tests; - -use frame_system::pallet_prelude::BlockNumberFor; -use polkadot_primitives::CoreIndex; - -use crate::{ - configuration, paras, - scheduler::common::{Assignment, AssignmentProvider}, -}; - -pub use pallet::*; - -#[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 + configuration::Config + paras::Config {} -} - -impl AssignmentProvider> for Pallet { - fn pop_assignment_for_core(core_idx: CoreIndex) -> Option { - paras::Parachains::::get() - .get(core_idx.0 as usize) - .copied() - .map(Assignment::Bulk) - } - - fn report_processed(_: Assignment) {} - - /// Bulk assignment has no need to push the assignment back on a session change, - /// this is a no-op in the case of a bulk assignment slot. - fn push_back_assignment(_: Assignment) {} - - #[cfg(any(feature = "runtime-benchmarks", test))] - fn get_mock_assignment(_: CoreIndex, para_id: polkadot_primitives::Id) -> Assignment { - Assignment::Bulk(para_id) - } - - fn session_core_count() -> u32 { - paras::Parachains::::decode_len().unwrap_or(0) as u32 - } -} diff --git a/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs b/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs deleted file mode 100644 index d984fd9232c3..000000000000 --- a/polkadot/runtime/parachains/src/assigner_parachains/mock_helpers.rs +++ /dev/null @@ -1,84 +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 . - -//! Helper functions for tests - -use crate::{ - mock::MockGenesisConfig, - paras::{ParaGenesisArgs, ParaKind}, -}; - -use polkadot_primitives::{Balance, HeadData, ValidationCode}; -use sp_runtime::Perbill; - -fn default_genesis_config() -> MockGenesisConfig { - MockGenesisConfig { - configuration: crate::configuration::GenesisConfig { - config: crate::configuration::HostConfiguration { ..Default::default() }, - }, - ..Default::default() - } -} - -#[derive(Debug)] -pub struct GenesisConfigBuilder { - pub on_demand_cores: u32, - pub on_demand_base_fee: Balance, - pub on_demand_fee_variability: Perbill, - pub on_demand_max_queue_size: u32, - pub on_demand_target_queue_utilization: Perbill, - pub onboarded_on_demand_chains: Vec, -} - -impl Default for GenesisConfigBuilder { - fn default() -> Self { - Self { - on_demand_cores: 10, - on_demand_base_fee: 10_000, - on_demand_fee_variability: Perbill::from_percent(1), - on_demand_max_queue_size: 100, - on_demand_target_queue_utilization: Perbill::from_percent(25), - onboarded_on_demand_chains: vec![], - } - } -} - -impl GenesisConfigBuilder { - pub(super) fn build(self) -> MockGenesisConfig { - let mut genesis = default_genesis_config(); - let config = &mut genesis.configuration.config; - config.scheduler_params.num_cores = self.on_demand_cores; - config.scheduler_params.on_demand_base_fee = self.on_demand_base_fee; - config.scheduler_params.on_demand_fee_variability = self.on_demand_fee_variability; - config.scheduler_params.on_demand_queue_max_size = self.on_demand_max_queue_size; - config.scheduler_params.on_demand_target_queue_utilization = - self.on_demand_target_queue_utilization; - - let paras = &mut genesis.paras.paras; - for para_id in self.onboarded_on_demand_chains { - paras.push(( - para_id, - ParaGenesisArgs { - genesis_head: HeadData::from(vec![0u8]), - validation_code: ValidationCode::from(vec![0u8]), - para_kind: ParaKind::Parathread, - }, - )) - } - - genesis - } -} diff --git a/polkadot/runtime/parachains/src/assigner_parachains/tests.rs b/polkadot/runtime/parachains/src/assigner_parachains/tests.rs deleted file mode 100644 index 817e43a7138d..000000000000 --- a/polkadot/runtime/parachains/src/assigner_parachains/tests.rs +++ /dev/null @@ -1,112 +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 super::*; -use crate::{ - assigner_parachains::mock_helpers::GenesisConfigBuilder, - initializer::SessionChangeNotification, - mock::{ - new_test_ext, ParachainsAssigner, Paras, ParasShared, RuntimeOrigin, Scheduler, System, - }, - paras::{ParaGenesisArgs, ParaKind}, -}; -use alloc::collections::btree_map::BTreeMap; -use frame_support::{assert_ok, pallet_prelude::*}; -use polkadot_primitives::{BlockNumber, Id as ParaId, SessionIndex, ValidationCode}; - -fn schedule_blank_para(id: ParaId, parakind: ParaKind) { - let validation_code: ValidationCode = vec![1, 2, 3].into(); - assert_ok!(Paras::schedule_para_initialize( - id, - ParaGenesisArgs { - genesis_head: Vec::new().into(), - validation_code: validation_code.clone(), - para_kind: parakind, - } - )); - - assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), validation_code)); -} - -fn run_to_block( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, -) { - while System::block_number() < to { - let b = System::block_number(); - - Scheduler::initializer_finalize(); - Paras::initializer_finalize(b); - - if let Some(notification) = new_session(b + 1) { - let mut notification_with_session_index = notification; - // We will make every session change trigger an action queue. Normally this may require - // 2 or more session changes. - if notification_with_session_index.session_index == SessionIndex::default() { - notification_with_session_index.session_index = ParasShared::scheduled_session(); - } - Paras::initializer_on_new_session(¬ification_with_session_index); - Scheduler::initializer_on_new_session(¬ification_with_session_index); - } - - System::on_finalize(b); - - System::on_initialize(b + 1); - System::set_block_number(b + 1); - - Paras::initializer_initialize(b + 1); - Scheduler::initializer_initialize(b + 1); - - // In the real runtime this is expected to be called by the `InclusionInherent` pallet. - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); - } -} - -// This and the scheduler test schedule_schedules_including_just_freed together -// ensure that next_up_on_available and next_up_on_time_out will always be -// filled with scheduler claims for lease holding parachains. (Removes the need -// for two other scheduler tests) -#[test] -fn parachains_assigner_pop_assignment_is_always_some() { - let core_index = CoreIndex(0); - let para_id = ParaId::from(10); - let expected_assignment = Assignment::Bulk(para_id); - - new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { - // Register the para_id as a lease holding parachain - schedule_blank_para(para_id, ParaKind::Parachain); - - assert!(!Paras::is_parachain(para_id)); - run_to_block(10, |n| if n == 10 { Some(Default::default()) } else { None }); - assert!(Paras::is_parachain(para_id)); - - for _ in 0..20 { - assert!( - ParachainsAssigner::pop_assignment_for_core(core_index) == - Some(expected_assignment.clone()) - ); - } - - run_to_block(20, |n| if n == 20 { Some(Default::default()) } else { None }); - - for _ in 0..20 { - assert!( - ParachainsAssigner::pop_assignment_for_core(core_index) == - Some(expected_assignment.clone()) - ); - } - }); -} diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 1654590d109e..fa9497f8ccd5 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -18,7 +18,10 @@ use crate::{ configuration, inclusion, initializer, paras, paras::ParaKind, paras_inherent, - scheduler::{self, common::AssignmentProvider, CoreOccupied, ParasEntry}, + scheduler::{ + self, + common::{Assignment, AssignmentProvider}, + }, session_info, shared, }; use alloc::{ @@ -138,8 +141,6 @@ pub(crate) struct BenchBuilder { /// Make every candidate include a code upgrade by setting this to `Some` where the interior /// value is the byte length of the new code. code_upgrade: Option, - /// Specifies whether the claimqueue should be filled. - fill_claimqueue: bool, /// Cores which should not be available when being populated with pending candidates. unavailable_cores: Vec, /// Use v2 candidate descriptor. @@ -178,7 +179,6 @@ impl BenchBuilder { backed_in_inherent_paras: Default::default(), elastic_paras: Default::default(), code_upgrade: None, - fill_claimqueue: true, unavailable_cores: vec![], candidate_descriptor_v2: false, candidate_modifier: None, @@ -322,13 +322,6 @@ impl BenchBuilder { self.max_validators() / self.max_validators_per_core() } - /// Set whether the claim queue should be filled. - #[cfg(not(feature = "runtime-benchmarks"))] - pub(crate) fn set_fill_claimqueue(mut self, f: bool) -> Self { - self.fill_claimqueue = f; - self - } - /// Get the minimum number of validity votes in order for a backed candidate to be included. #[cfg(feature = "runtime-benchmarks")] pub(crate) fn fallback_min_backing_votes() -> u32 { @@ -340,10 +333,13 @@ impl BenchBuilder { HeadData(vec![0xFF; max_head_size as usize]) } - fn candidate_descriptor_mock(candidate_descriptor_v2: bool) -> CandidateDescriptorV2 { + fn candidate_descriptor_mock( + para_id: ParaId, + candidate_descriptor_v2: bool, + ) -> CandidateDescriptorV2 { if candidate_descriptor_v2 { CandidateDescriptorV2::new( - 0.into(), + para_id, Default::default(), CoreIndex(200), 2, @@ -356,7 +352,7 @@ impl BenchBuilder { } else { // Convert v1 to v2. CandidateDescriptor:: { - para_id: 0.into(), + para_id, relay_parent: Default::default(), collator: junk_collator(), persisted_validation_data_hash: Default::default(), @@ -373,6 +369,7 @@ impl BenchBuilder { /// Create a mock of `CandidatePendingAvailability`. fn candidate_availability_mock( + para_id: ParaId, group_idx: GroupIndex, core_idx: CoreIndex, candidate_hash: CandidateHash, @@ -381,15 +378,16 @@ impl BenchBuilder { candidate_descriptor_v2: bool, ) -> inclusion::CandidatePendingAvailability> { inclusion::CandidatePendingAvailability::>::new( - core_idx, // core - candidate_hash, // hash - Self::candidate_descriptor_mock(candidate_descriptor_v2), // candidate descriptor - commitments, // commitments - availability_votes, // availability votes - Default::default(), // backers - Zero::zero(), // relay parent - One::one(), /* relay chain block this - * was backed in */ + core_idx, // core + candidate_hash, // hash + Self::candidate_descriptor_mock(para_id, candidate_descriptor_v2), /* candidate descriptor */ + commitments, // commitments + availability_votes, /* availability + * votes */ + Default::default(), // backers + Zero::zero(), // relay parent + One::one(), /* relay chain block this + * was backed in */ group_idx, // backing group ) } @@ -416,6 +414,7 @@ impl BenchBuilder { hrmp_watermark: 0u32.into(), }; let candidate_availability = Self::candidate_availability_mock( + para_id, group_idx, core_idx, candidate_hash, @@ -886,14 +885,11 @@ impl BenchBuilder { extra_cores; assert!(used_cores <= max_cores); - let fill_claimqueue = self.fill_claimqueue; // NOTE: there is an n+2 session delay for these actions to take effect. // We are currently in Session 0, so these changes will take effect in Session 2. Self::setup_para_ids(used_cores - extra_cores); - configuration::ActiveConfig::::mutate(|c| { - c.scheduler_params.num_cores = used_cores as u32; - }); + configuration::Pallet::::set_coretime_cores_unchecked(used_cores as u32).unwrap(); let validator_ids = generate_validator_pairs::(self.max_validators()); let target_session = SessionIndex::from(self.target_session); @@ -902,7 +898,7 @@ impl BenchBuilder { let bitfields = builder.create_availability_bitfields( &builder.backed_and_concluding_paras, &builder.elastic_paras, - used_cores, + scheduler::Pallet::::num_availability_cores(), ); let mut backed_in_inherent = BTreeMap::new(); @@ -930,66 +926,57 @@ impl BenchBuilder { assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores - extra_cores); - // Mark all the used cores as occupied. We expect that there are - // `backed_and_concluding_paras` that are pending availability and that there are - // `used_cores - backed_and_concluding_paras ` which are about to be disputed. - let now = frame_system::Pallet::::block_number() + One::one(); - + // Sanity check that the occupied cores reported by the inclusion module are what we expect + // to be. let mut core_idx = 0u32; let elastic_paras = &builder.elastic_paras; - // Assign potentially multiple cores to same parachains, - let cores = all_cores + + let mut occupied_cores = inclusion::Pallet::::get_occupied_cores() + .map(|(core, candidate)| (core, candidate.candidate_descriptor().para_id())) + .collect::>(); + occupied_cores.sort_by(|(core_a, _), (core_b, _)| core_a.0.cmp(&core_b.0)); + + let mut expected_cores = all_cores .iter() .flat_map(|(para_id, _)| { (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) .map(|_para_local_core_idx| { - let ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - // Load an assignment into provider so that one is present to pop - let assignment = - ::AssignmentProvider::get_mock_assignment( - CoreIndex(core_idx), - ParaId::from(*para_id), - ); + let old_core_idx = core_idx; core_idx += 1; - CoreOccupied::Paras(ParasEntry::new(assignment, now + ttl)) + (CoreIndex(old_core_idx), ParaId::from(*para_id)) }) - .collect::>>() + .collect::>() }) - .collect::>>(); + .collect::>(); - scheduler::AvailabilityCores::::set(cores); + expected_cores.sort_by(|(core_a, _), (core_b, _)| core_a.0.cmp(&core_b.0)); - core_idx = 0u32; + assert_eq!(expected_cores, occupied_cores); // We need entries in the claim queue for those: all_cores.append(&mut builder.backed_in_inherent_paras.clone()); - if fill_claimqueue { - let cores = all_cores - .keys() - .flat_map(|para_id| { - (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) - .map(|_para_local_core_idx| { - let ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - // Load an assignment into provider so that one is present to pop - let assignment = - ::AssignmentProvider::get_mock_assignment( - CoreIndex(core_idx), - ParaId::from(*para_id), - ); - - core_idx += 1; - ( - CoreIndex(core_idx - 1), - [ParasEntry::new(assignment, now + ttl)].into(), - ) - }) - .collect::>)>>() - }) - .collect::>>>(); + let mut core_idx = 0u32; + let cores = all_cores + .keys() + .flat_map(|para_id| { + (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) + .map(|_para_local_core_idx| { + // Load an assignment into provider so that one is present to pop + let assignment = + ::AssignmentProvider::get_mock_assignment( + CoreIndex(core_idx), + ParaId::from(*para_id), + ); - scheduler::ClaimQueue::::set(cores); - } + core_idx += 1; + (CoreIndex(core_idx - 1), [assignment].into()) + }) + .collect::)>>() + }) + .collect::>>(); + + scheduler::ClaimQueue::::set(cores); Bench:: { data: ParachainsInherentData { diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 36888247580e..e5cf7c4d276e 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -337,8 +337,6 @@ pub enum InconsistentError { ZeroMinimumBackingVotes, /// `executor_params` are inconsistent. InconsistentExecutorParams { inner: ExecutorParamError }, - /// TTL should be bigger than lookahead - LookaheadExceedsTTL, /// Lookahead is zero, while it must be at least 1 for parachains to work. LookaheadZero, /// Passed in queue size for on-demand was too large. @@ -434,10 +432,6 @@ where return Err(InconsistentExecutorParams { inner }) } - if self.scheduler_params.ttl < self.scheduler_params.lookahead.into() { - return Err(LookaheadExceedsTTL) - } - if self.scheduler_params.lookahead == 0 { return Err(LookaheadZero) } @@ -686,18 +680,7 @@ pub mod pallet { Self::set_coretime_cores_unchecked(new) } - /// Set the max number of times a claim may timeout on a core before it is abandoned - #[pallet::call_index(7)] - #[pallet::weight(( - T::WeightInfo::set_config_with_u32(), - DispatchClass::Operational, - ))] - pub fn set_max_availability_timeouts(origin: OriginFor, new: u32) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.scheduler_params.max_availability_timeouts = new; - }) - } + // Call index 7 used to be `set_max_availability_timeouts`, which was removed. /// Set the parachain validator-group rotation frequency #[pallet::call_index(8)] @@ -1193,18 +1176,8 @@ pub mod pallet { config.scheduler_params.on_demand_target_queue_utilization = new; }) } - /// Set the on demand (parathreads) ttl in the claimqueue. - #[pallet::call_index(51)] - #[pallet::weight(( - T::WeightInfo::set_config_with_block_number(), - DispatchClass::Operational - ))] - pub fn set_on_demand_ttl(origin: OriginFor, new: BlockNumberFor) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.scheduler_params.ttl = new; - }) - } + + // Call index 51 used to be `set_on_demand_ttl`, which was removed. /// Set the minimum backing votes threshold. #[pallet::call_index(52)] diff --git a/polkadot/runtime/parachains/src/configuration/migration/v12.rs b/polkadot/runtime/parachains/src/configuration/migration/v12.rs index 111b1a199966..d1e0cf10a0ff 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v12.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v12.rs @@ -143,6 +143,7 @@ fn migrate_to_v12() -> Weight { minimum_backing_votes : pre.minimum_backing_votes, node_features : pre.node_features, approval_voting_params : pre.approval_voting_params, + #[allow(deprecated)] scheduler_params: SchedulerParams { group_rotation_frequency : pre.group_rotation_frequency, paras_availability_period : pre.paras_availability_period, @@ -231,7 +232,10 @@ mod tests { assert_eq!(v12.scheduler_params.paras_availability_period, 4); assert_eq!(v12.scheduler_params.lookahead, 1); assert_eq!(v12.scheduler_params.num_cores, 1); - assert_eq!(v12.scheduler_params.max_availability_timeouts, 0); + #[allow(deprecated)] + { + assert_eq!(v12.scheduler_params.max_availability_timeouts, 0); + } assert_eq!(v12.scheduler_params.on_demand_queue_max_size, 10_000); assert_eq!( v12.scheduler_params.on_demand_target_queue_utilization, @@ -239,7 +243,10 @@ mod tests { ); assert_eq!(v12.scheduler_params.on_demand_fee_variability, Perbill::from_percent(3)); assert_eq!(v12.scheduler_params.on_demand_base_fee, 10_000_000); - assert_eq!(v12.scheduler_params.ttl, 5); + #[allow(deprecated)] + { + assert_eq!(v12.scheduler_params.ttl, 5); + } } #[test] @@ -282,6 +289,7 @@ mod tests { for (_, v12) in configs_to_check { #[rustfmt::skip] + #[allow(deprecated)] { assert_eq!(v11.max_code_size , v12.max_code_size); assert_eq!(v11.max_head_data_size , v12.max_head_data_size); diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index 0d20399e471b..a8689a04fe04 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -316,13 +316,14 @@ fn setting_pending_config_members() { approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 }, minimum_backing_votes: 5, node_features: bitvec![u8, Lsb0; 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], + #[allow(deprecated)] scheduler_params: SchedulerParams { group_rotation_frequency: 20, paras_availability_period: 10, max_validators_per_core: None, lookahead: 3, num_cores: 2, - max_availability_timeouts: 5, + max_availability_timeouts: 0, on_demand_queue_max_size: 10_000u32, on_demand_base_fee: 10_000_000u128, on_demand_fee_variability: Perbill::from_percent(3), @@ -355,11 +356,6 @@ fn setting_pending_config_members() { new_config.scheduler_params.num_cores, ) .unwrap(); - Configuration::set_max_availability_timeouts( - RuntimeOrigin::root(), - new_config.scheduler_params.max_availability_timeouts, - ) - .unwrap(); Configuration::set_group_rotation_frequency( RuntimeOrigin::root(), new_config.scheduler_params.group_rotation_frequency, diff --git a/polkadot/runtime/parachains/src/coretime/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index d4be135aad65..c3a1ebe82432 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -19,8 +19,6 @@ pub use v_coretime::{GetLegacyLease, MigrateToCoretime}; mod v_coretime { - #[cfg(feature = "try-runtime")] - use crate::scheduler::common::AssignmentProvider; use crate::{ assigner_coretime, configuration, coretime::{mk_coretime_call, Config, PartsOf57600, WeightInfo}, @@ -44,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 { @@ -64,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 @@ -97,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() { @@ -108,7 +108,7 @@ mod v_coretime { } log::info!("Migrating existing parachains to coretime."); - migrate_to_coretime::() + migrate_to_coretime::() } #[cfg(feature = "try-runtime")] @@ -142,7 +142,8 @@ mod v_coretime { let dmp_queue_size = crate::dmp::Pallet::::dmq_contents(T::BrokerId::get().into()).len() as u32; - let new_core_count = assigner_coretime::Pallet::::session_core_count(); + let config = configuration::ActiveConfig::::get(); + let new_core_count = config.scheduler_params.num_cores; ensure!(new_core_count == prev_core_count, "Total number of cores need to not change."); ensure!( dmp_queue_size > prev_dmp_queue_size, @@ -158,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 { @@ -199,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); } @@ -216,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> { @@ -301,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..966b7997a277 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::*; @@ -149,11 +136,6 @@ pub mod pallet { type AssetTransactor: TransactAsset; /// AccountId to Location converter type AccountToLocation: for<'a> TryConvert<&'a Self::AccountId, Location>; - - /// Maximum weight for any XCM transact call that should be executed on the coretime chain. - /// - /// Basically should be `max_weight(set_leases, reserve, notify_core_count)`. - type MaxXcmTransactWeight: Get; } #[pallet::event] @@ -351,7 +333,6 @@ 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(), call: BrokerRuntimePallets::Broker(call).encode().into(), } } @@ -362,7 +343,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.rs b/polkadot/runtime/parachains/src/disputes.rs index f86573dadf56..d5a3f31e5943 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -1309,3 +1309,11 @@ fn check_signature( res } + +#[cfg(all(not(feature = "runtime-benchmarks"), test))] +// Test helper for clearing the on-chain dispute data. +pub(crate) fn clear_dispute_storage() { + let _ = Disputes::::clear(u32::MAX, None); + let _ = BackersOnDisputes::::clear(u32::MAX, None); + let _ = Included::::clear(u32::MAX, None); +} diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index 4b76fb47e1f8..2e09ea667f74 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -653,7 +653,7 @@ impl Default for SlashingReportHandler { impl HandleReports for SlashingReportHandler where - T: Config + frame_system::offchain::SendTransactionTypes>, + T: Config + frame_system::offchain::CreateInherent>, R: ReportOffence< T::AccountId, T::KeyOwnerIdentification, @@ -685,7 +685,7 @@ where dispute_proof: DisputeProof, key_owner_proof: ::KeyOwnerProof, ) -> Result<(), sp_runtime::TryRuntimeError> { - use frame_system::offchain::SubmitTransaction; + use frame_system::offchain::{CreateInherent, SubmitTransaction}; let session_index = dispute_proof.time_slot.session_index; let validator_index = dispute_proof.validator_index.0; @@ -696,7 +696,8 @@ where key_owner_proof, }; - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { + let xt = >>::create_inherent(call.into()); + match SubmitTransaction::>::submit_transaction(xt) { Ok(()) => { log::info!( target: LOG_TARGET, diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 36f874b8db1e..8ad9711a0f38 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -46,11 +46,11 @@ 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, }, - well_known_keys, CandidateCommitments, CandidateHash, CoreIndex, GroupIndex, Hash, HeadData, + well_known_keys, CandidateCommitments, CandidateHash, CoreIndex, GroupIndex, HeadData, Id as ParaId, SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, ValidatorIndex, ValidityAttestation, }; @@ -161,16 +161,6 @@ impl CandidatePendingAvailability { self.relay_parent_number.clone() } - /// Get the candidate backing group. - pub(crate) fn backing_group(&self) -> GroupIndex { - self.backing_group - } - - /// Get the candidate's backers. - pub(crate) fn backers(&self) -> &BitVec { - &self.backers - } - #[cfg(any(feature = "runtime-benchmarks", test))] pub(crate) fn new( core: CoreIndex, @@ -207,24 +197,6 @@ pub trait RewardValidators { fn reward_bitfields(validators: impl IntoIterator); } -/// Helper return type for `process_candidates`. -#[derive(Encode, Decode, PartialEq, TypeInfo)] -#[cfg_attr(test, derive(Debug))] -pub(crate) struct ProcessedCandidates { - pub(crate) core_indices: Vec<(CoreIndex, ParaId)>, - pub(crate) candidate_receipt_with_backing_validator_indices: - Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, -} - -impl Default for ProcessedCandidates { - fn default() -> Self { - Self { - core_indices: Vec::new(), - candidate_receipt_with_backing_validator_indices: Vec::new(), - } - } -} - /// Reads the footprint of queues for a specific origin type. pub trait QueueFootprinter { type Origin; @@ -440,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 { @@ -473,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") - }, } } } @@ -514,6 +475,14 @@ impl Pallet { T::MessageQueue::sweep_queue(AggregateMessageOrigin::Ump(UmpQueueId::Para(para))); } + pub(crate) fn get_occupied_cores( + ) -> impl Iterator>)> + { + PendingAvailability::::iter_values().flat_map(|pending_candidates| { + pending_candidates.into_iter().map(|c| (c.core, c.clone())) + }) + } + /// Extract the freed cores based on cores that became available. /// /// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`! @@ -640,12 +609,15 @@ impl Pallet { candidates: &BTreeMap, CoreIndex)>>, group_validators: GV, core_index_enabled: bool, - ) -> Result, DispatchError> + ) -> Result< + Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, + DispatchError, + > where GV: Fn(GroupIndex) -> Option>, { if candidates.is_empty() { - return Ok(ProcessedCandidates::default()) + return Ok(Default::default()) } let now = frame_system::Pallet::::block_number(); @@ -654,7 +626,6 @@ impl Pallet { // Collect candidate receipts with backers. let mut candidate_receipt_with_backing_validator_indices = Vec::with_capacity(candidates.len()); - let mut core_indices = Vec::with_capacity(candidates.len()); for (para_id, para_candidates) in candidates { let mut latest_head_data = match Self::para_latest_head_data(para_id) { @@ -708,7 +679,6 @@ impl Pallet { latest_head_data = candidate.candidate().commitments.head_data.clone(); candidate_receipt_with_backing_validator_indices .push((candidate.receipt(), backer_idx_and_attestation)); - core_indices.push((*core, *para_id)); // Update storage now PendingAvailability::::mutate(¶_id, |pending_availability| { @@ -743,10 +713,7 @@ impl Pallet { } } - Ok(ProcessedCandidates:: { - core_indices, - candidate_receipt_with_backing_validator_indices, - }) + Ok(candidate_receipt_with_backing_validator_indices) } // Get the latest backed output head data of this para (including pending availability). @@ -947,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) { @@ -1019,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(|_| { @@ -1173,7 +1119,9 @@ impl Pallet { /// Returns the first `CommittedCandidateReceipt` pending availability for the para provided, if /// any. - pub(crate) fn candidate_pending_availability( + /// A para_id could have more than one candidates pending availability, if it's using elastic + /// scaling. These candidates form a chain. This function returns the first in the chain. + pub(crate) fn first_candidate_pending_availability( para: ParaId, ) -> Option> { PendingAvailability::::get(¶).and_then(|p| { @@ -1201,24 +1149,6 @@ impl Pallet { }) .unwrap_or_default() } - - /// Returns the metadata around the first candidate pending availability for the - /// para provided, if any. - pub(crate) fn pending_availability( - para: ParaId, - ) -> Option>> { - PendingAvailability::::get(¶).and_then(|p| p.get(0).cloned()) - } - - /// Returns the metadata around the candidate pending availability occupying the supplied core, - /// if any. - pub(crate) fn pending_availability_with_core( - para: ParaId, - core: CoreIndex, - ) -> Option>> { - PendingAvailability::::get(¶) - .and_then(|p| p.iter().find(|c| c.core == core).cloned()) - } } const fn availability_threshold(n_validators: usize) -> usize { diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 87d21e209a49..8513d2dad91d 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -39,7 +39,7 @@ use assert_matches::assert_matches; use codec::DecodeAll; use frame_support::assert_noop; use polkadot_primitives::{ - BlockNumber, CandidateCommitments, CollatorId, CollatorSignature, + vstaging::MutateDescriptorV2, BlockNumber, CandidateCommitments, CollatorId, CollatorSignature, CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement, ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID, }; @@ -1267,7 +1267,7 @@ fn candidate_checks() { &group_validators, false ), - Ok(ProcessedCandidates::default()) + Ok(Default::default()) ); // Check candidate ordering @@ -1563,20 +1563,16 @@ fn candidate_checks() { None, ); - let ProcessedCandidates { - core_indices: occupied_cores, - candidate_receipt_with_backing_validator_indices, - } = ParaInclusion::process_candidates( - &allowed_relay_parents, - &vec![(thread_a_assignment.0, vec![(backed.clone(), thread_a_assignment.1)])] - .into_iter() - .collect(), - &group_validators, - false, - ) - .expect("candidate is accepted with bad collator signature"); - - assert_eq!(occupied_cores, vec![(CoreIndex::from(2), thread_a)]); + let candidate_receipt_with_backing_validator_indices = + ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![(thread_a_assignment.0, vec![(backed.clone(), thread_a_assignment.1)])] + .into_iter() + .collect(), + &group_validators, + false, + ) + .expect("candidate is accepted with bad collator signature"); let mut expected = std::collections::HashMap::< CandidateHash, @@ -1924,10 +1920,7 @@ fn backing_works() { } }; - let ProcessedCandidates { - core_indices: occupied_cores, - candidate_receipt_with_backing_validator_indices, - } = ParaInclusion::process_candidates( + let candidate_receipt_with_backing_validator_indices = ParaInclusion::process_candidates( &allowed_relay_parents, &backed_candidates, &group_validators, @@ -1935,15 +1928,6 @@ fn backing_works() { ) .expect("candidates scheduled, in order, and backed"); - assert_eq!( - occupied_cores, - vec![ - (CoreIndex::from(0), chain_a), - (CoreIndex::from(1), chain_b), - (CoreIndex::from(2), thread_a) - ] - ); - // Transform the votes into the setup we expect let expected = { let mut intermediate = std::collections::HashMap::< @@ -2224,10 +2208,7 @@ fn backing_works_with_elastic_scaling_mvp() { } }; - let ProcessedCandidates { - core_indices: occupied_cores, - candidate_receipt_with_backing_validator_indices, - } = ParaInclusion::process_candidates( + let candidate_receipt_with_backing_validator_indices = ParaInclusion::process_candidates( &allowed_relay_parents, &backed_candidates, &group_validators, @@ -2235,16 +2216,6 @@ fn backing_works_with_elastic_scaling_mvp() { ) .expect("candidates scheduled, in order, and backed"); - // Both b candidates will be backed. - assert_eq!( - occupied_cores, - vec![ - (CoreIndex::from(0), chain_a), - (CoreIndex::from(1), chain_b), - (CoreIndex::from(2), chain_b), - ] - ); - // Transform the votes into the setup we expect let mut expected = std::collections::HashMap::< CandidateHash, @@ -2420,18 +2391,15 @@ fn can_include_candidate_with_ok_code_upgrade() { None, ); - let ProcessedCandidates { core_indices: occupied_cores, .. } = - ParaInclusion::process_candidates( - &allowed_relay_parents, - &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] - .into_iter() - .collect::>(), - group_validators, - false, - ) - .expect("candidates scheduled, in order, and backed"); - - assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); + let _ = ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] + .into_iter() + .collect::>(), + group_validators, + false, + ) + .expect("candidates scheduled, in order, and backed"); let backers = { let num_backers = effective_minimum_backing_votes( @@ -2846,7 +2814,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { None, ); - let ProcessedCandidates { core_indices: occupied_cores, .. } = + let _ = ParaInclusion::process_candidates( &allowed_relay_parents, &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] @@ -2857,8 +2825,6 @@ fn para_upgrade_delay_scheduled_from_inclusion() { ) .expect("candidates scheduled, in order, and backed"); - assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); - // Run a couple of blocks before the inclusion. run_to_block(7, |_| None); diff --git a/polkadot/runtime/parachains/src/initializer.rs b/polkadot/runtime/parachains/src/initializer.rs index 340f727097b5..6ee245fb5230 100644 --- a/polkadot/runtime/parachains/src/initializer.rs +++ b/polkadot/runtime/parachains/src/initializer.rs @@ -87,10 +87,10 @@ impl> Default for SessionChangeNotification, - queued: Vec, - session_index: SessionIndex, +pub(crate) struct BufferedSessionChange { + pub validators: Vec, + pub queued: Vec, + pub session_index: SessionIndex, } pub trait WeightInfo { @@ -149,7 +149,7 @@ pub mod pallet { #[pallet::storage] pub(super) type HasInitialized = StorageValue<_, ()>; - /// Buffered session changes along with the block number at which they should be applied. + /// Buffered session changes. /// /// Typically this will be empty or one element long. Apart from that this item never hits /// the storage. @@ -157,7 +157,7 @@ pub mod pallet { /// However this is a `Vec` regardless to handle various edge cases that may occur at runtime /// upgrade boundaries or if governance intervenes. #[pallet::storage] - pub(super) type BufferedSessionChanges = + pub(crate) type BufferedSessionChanges = StorageValue<_, Vec, ValueQuery>; #[pallet::hooks] @@ -254,9 +254,6 @@ impl Pallet { buf }; - // inform about upcoming new session - scheduler::Pallet::::pre_new_session(); - let configuration::SessionChangeOutcome { prev_config, new_config } = configuration::Pallet::::initializer_on_new_session(&session_index); let new_config = new_config.unwrap_or_else(|| prev_config.clone()); @@ -328,6 +325,11 @@ impl Pallet { { Self::on_new_session(changed, session_index, validators, queued) } + + /// Return whether at the end of this block a new session will be initialized. + pub(crate) fn upcoming_session_change() -> bool { + !BufferedSessionChanges::::get().is_empty() + } } impl sp_runtime::BoundToRuntimeAppPublic for Pallet { diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index f1162e1cc215..828c0b9bcef2 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -24,7 +24,6 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod assigner_coretime; -pub mod assigner_parachains; pub mod configuration; pub mod coretime; pub mod disputes; diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs index 75c9e3a5c9b9..d701e1f9bd80 100644 --- a/polkadot/runtime/parachains/src/mock.rs +++ b/polkadot/runtime/parachains/src/mock.rs @@ -17,7 +17,7 @@ //! Mocks for all the traits. use crate::{ - assigner_coretime, assigner_parachains, configuration, coretime, disputes, dmp, hrmp, + assigner_coretime, configuration, coretime, disputes, dmp, hrmp, inclusion::{self, AggregateMessageOrigin, UmpQueueId}, initializer, on_demand, origin, paras, paras::ParaKind, @@ -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, }; @@ -76,7 +78,6 @@ frame_support::construct_runtime!( ParaInherent: paras_inherent, Scheduler: scheduler, MockAssigner: mock_assigner, - ParachainsAssigner: assigner_parachains, OnDemand: on_demand, CoretimeAssigner: assigner_coretime, Coretime: coretime, @@ -90,12 +91,21 @@ frame_support::construct_runtime!( } ); -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + 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) + } } parameter_types! { @@ -252,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, ()> { @@ -390,8 +400,6 @@ impl pallet_message_queue::Config for Test { type IdleMaxServiceWeight = (); } -impl assigner_parachains::Config for Test {} - parameter_types! { pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); // Production chains should keep this numbar around twice the @@ -413,7 +421,6 @@ impl assigner_coretime::Config for Test {} parameter_types! { pub const BrokerId: u32 = 10u32; - pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000); } pub struct BrokerPot; @@ -430,7 +437,6 @@ impl coretime::Config for Test { type BrokerId = BrokerId; type WeightInfo = crate::coretime::TestWeightInfo; type SendXcm = DummyXcmSender; - type MaxXcmTransactWeight = MaxXcmTransactWeight; type BrokerPotLocation = BrokerPot; type AssetTransactor = (); type AccountToLocation = (); @@ -511,9 +517,6 @@ pub mod mock_assigner { #[pallet::storage] pub(super) type MockAssignmentQueue = StorageValue<_, VecDeque, ValueQuery>; - - #[pallet::storage] - pub(super) type MockCoreCount = StorageValue<_, u32, OptionQuery>; } impl Pallet { @@ -522,12 +525,6 @@ pub mod mock_assigner { pub fn add_test_assignment(assignment: Assignment) { MockAssignmentQueue::::mutate(|queue| queue.push_back(assignment)); } - - // Allows for customized core count in scheduler tests, rather than a core count - // derived from on-demand config + parachain count. - pub fn set_core_count(count: u32) { - MockCoreCount::::set(Some(count)); - } } impl AssignmentProvider for Pallet { @@ -545,20 +542,18 @@ pub mod mock_assigner { } // We don't care about core affinity in the test assigner - fn report_processed(_assignment: Assignment) {} + fn report_processed(_: Assignment) {} - // The results of this are tested in on_demand tests. No need to represent it - // in the mock assigner. - fn push_back_assignment(_assignment: Assignment) {} + fn push_back_assignment(assignment: Assignment) { + Self::add_test_assignment(assignment); + } #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(_: CoreIndex, para_id: ParaId) -> Assignment { Assignment::Bulk(para_id) } - fn session_core_count() -> u32 { - MockCoreCount::::get().unwrap_or(5) - } + fn assignment_duplicated(_: &Assignment) {} } } diff --git a/polkadot/runtime/parachains/src/on_demand/mod.rs b/polkadot/runtime/parachains/src/on_demand/mod.rs index dc046c194fd0..66400eb00fd9 100644 --- a/polkadot/runtime/parachains/src/on_demand/mod.rs +++ b/polkadot/runtime/parachains/src/on_demand/mod.rs @@ -317,6 +317,11 @@ where Some(assignment) } + /// Report that an assignment was duplicated by the scheduler. + pub fn assignment_duplicated(para_id: ParaId, core_index: CoreIndex) { + Pallet::::increase_affinity(para_id, core_index); + } + /// Report that the `para_id` & `core_index` combination was processed. /// /// This should be called once it is clear that the assignment won't get pushed back anymore. diff --git a/polkadot/runtime/parachains/src/on_demand/tests.rs b/polkadot/runtime/parachains/src/on_demand/tests.rs index 974295411810..7da16942c7ad 100644 --- a/polkadot/runtime/parachains/src/on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/on_demand/tests.rs @@ -30,7 +30,6 @@ use crate::{ }, paras::{ParaGenesisArgs, ParaKind}, }; -use alloc::collections::btree_map::BTreeMap; use core::cmp::{Ord, Ordering}; use frame_support::{assert_noop, assert_ok}; use pallet_balances::Error as BalancesError; @@ -86,7 +85,7 @@ fn run_to_block( OnDemand::on_initialize(b + 1); // In the real runtime this is expected to be called by the `InclusionInherent` pallet. - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); + Scheduler::advance_claim_queue(&Default::default()); } } diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 5048656e6363..e0f244dbd863 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -615,7 +615,7 @@ pub mod pallet { frame_system::Config + configuration::Config + shared::Config - + frame_system::offchain::SendTransactionTypes> + + frame_system::offchain::CreateInherent> { type RuntimeEvent: From + IsType<::RuntimeEvent>; @@ -2177,9 +2177,8 @@ impl Pallet { ) { use frame_system::offchain::SubmitTransaction; - if let Err(e) = SubmitTransaction::>::submit_unsigned_transaction( - Call::include_pvf_check_statement { stmt, signature }.into(), - ) { + let xt = T::create_inherent(Call::include_pvf_check_statement { stmt, signature }.into()); + if let Err(e) = SubmitTransaction::>::submit_transaction(xt) { log::error!(target: LOG_TARGET, "Error submitting pvf check statement: {:?}", e,); } } diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index 266860061bed..485e7211c1d2 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -43,7 +43,8 @@ benchmarks! { // Variant over `v`, the number of dispute statements in a dispute statement set. This gives the // weight of a single dispute statement set. enter_variable_disputes { - let v in 10..BenchBuilder::::fallback_max_validators(); + // The number of statements needs to be at least a third of the validator set size. + let v in 400..BenchBuilder::::fallback_max_validators(); let scenario = BenchBuilder::::new() .set_dispute_sessions(&[2]) diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 2aca0f2c728a..4c1394fd1347 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -27,8 +27,7 @@ use crate::{ inclusion::{self, CandidateCheckContext}, initializer, metrics::METRICS, - paras, - scheduler::{self, FreedReason}, + paras, scheduler, shared::{self, AllowedRelayParentsTracker}, ParaId, }; @@ -38,6 +37,7 @@ use alloc::{ vec::Vec, }; use bitvec::prelude::BitVec; +use core::result::Result; use frame_support::{ defensive, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, @@ -105,15 +105,6 @@ impl DisputedBitfield { } } -/// The context in which the inherent data is checked or processed. -#[derive(PartialEq)] -pub enum ProcessInherentDataContext { - /// Enables filtering/limits weight of inherent up to maximum block weight. - /// Invariant: InherentWeight <= BlockWeight. - ProvideInherent, - /// Checks the InherentWeight invariant. - Enter, -} pub use pallet::*; #[frame_support::pallet] @@ -140,11 +131,9 @@ pub mod pallet { /// The hash of the submitted parent header doesn't correspond to the saved block hash of /// the parent. InvalidParentHeader, - /// The data given to the inherent will result in an overweight block. - InherentOverweight, - /// A candidate was filtered during inherent execution. This should have only been done + /// Inherent data was filtered during execution. This should have only been done /// during creation. - CandidatesFilteredDuringExecution, + InherentDataFilteredDuringExecution, /// Too many candidates supplied. UnscheduledCandidate, } @@ -253,9 +242,12 @@ pub mod pallet { ensure!(!Included::::exists(), Error::::TooManyInclusionInherents); Included::::set(Some(())); + let initial_data = data.clone(); - Self::process_inherent_data(data, ProcessInherentDataContext::Enter) - .map(|(_processed, post_info)| post_info) + Self::process_inherent_data(data).and_then(|(processed, post_info)| { + ensure!(initial_data == processed, Error::::InherentDataFilteredDuringExecution); + Ok(post_info) + }) } } } @@ -273,10 +265,7 @@ impl Pallet { return None }, }; - match Self::process_inherent_data( - parachains_inherent_data, - ProcessInherentDataContext::ProvideInherent, - ) { + match Self::process_inherent_data(parachains_inherent_data) { Ok((processed, _)) => Some(processed), Err(err) => { log::warn!(target: LOG_TARGET, "Processing inherent data failed: {:?}", err); @@ -290,21 +279,12 @@ impl Pallet { /// The given inherent data is processed and state is altered accordingly. If any data could /// not be applied (inconsistencies, weight limit, ...) it is removed. /// - /// When called from `create_inherent` the `context` must be set to - /// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent - /// is not overweight. - /// It is **mandatory** that calls from `enter` set `context` to - /// `ProcessInherentDataContext::Enter` to ensure the weight invariant is checked. - /// /// Returns: Result containing processed inherent data and weight, the processed inherent would /// consume. fn process_inherent_data( data: ParachainsInherentData>, - context: ProcessInherentDataContext, - ) -> core::result::Result< - (ParachainsInherentData>, PostDispatchInfo), - DispatchErrorWithPostInfo, - > { + ) -> Result<(ParachainsInherentData>, PostDispatchInfo), DispatchErrorWithPostInfo> + { #[cfg(feature = "runtime-metrics")] sp_io::init_tracing(); @@ -333,6 +313,27 @@ impl Pallet { let now = frame_system::Pallet::::block_number(); let config = configuration::ActiveConfig::::get(); + // Before anything else, update the allowed relay-parents. + { + let parent_number = now - One::one(); + let parent_storage_root = *parent_header.state_root(); + + shared::AllowedRelayParents::::mutate(|tracker| { + tracker.update( + parent_hash, + parent_storage_root, + scheduler::ClaimQueue::::get() + .into_iter() + .map(|(core_index, paras)| { + (core_index, paras.into_iter().map(|e| e.para_id()).collect()) + }) + .collect(), + parent_number, + config.async_backing_params.allowed_ancestry_len, + ); + }); + } + let candidates_weight = backed_candidates_weight::(&backed_candidates); let bitfields_weight = signed_bitfields_weight::(&bitfields); let disputes_weight = multi_dispute_statement_sets_weight::(&disputes); @@ -345,7 +346,7 @@ impl Pallet { log::debug!(target: LOG_TARGET, "Time weight before filter: {}, candidates + bitfields: {}, disputes: {}", weight_before_filtering.ref_time(), candidates_weight.ref_time() + bitfields_weight.ref_time(), disputes_weight.ref_time()); let current_session = shared::CurrentSessionIndex::::get(); - let expected_bits = scheduler::AvailabilityCores::::get().len(); + let expected_bits = scheduler::Pallet::::num_availability_cores(); let validator_public = shared::ActiveValidatorKeys::::get(); // We are assuming (incorrectly) to have all the weight (for the mandatory class or even @@ -390,7 +391,7 @@ impl Pallet { T::DisputesHandler::filter_dispute_data(set, post_conclusion_acceptance_period) }; - // Limit the disputes first, since the following statements depend on the votes include + // Limit the disputes first, since the following statements depend on the votes included // here. let (checked_disputes_sets, checked_disputes_sets_consumed_weight) = limit_and_sanitize_disputes::( @@ -399,7 +400,7 @@ impl Pallet { max_block_weight, ); - let mut all_weight_after = if context == ProcessInherentDataContext::ProvideInherent { + let mut all_weight_after = { // Assure the maximum block weight is adhered, by limiting bitfields and backed // candidates. Dispute statement sets were already limited before. let non_disputes_weight = apply_weight_limit::( @@ -427,23 +428,6 @@ impl Pallet { log::warn!(target: LOG_TARGET, "Post weight limiting weight is still too large, time: {}, size: {}", all_weight_after.ref_time(), all_weight_after.proof_size()); } all_weight_after - } else { - // This check is performed in the context of block execution. Ensures inherent weight - // invariants guaranteed by `create_inherent_data` for block authorship. - if weight_before_filtering.any_gt(max_block_weight) { - log::error!( - "Overweight para inherent data reached the runtime {:?}: {} > {}", - parent_hash, - weight_before_filtering, - max_block_weight - ); - } - - ensure!( - weight_before_filtering.all_lte(max_block_weight), - Error::::InherentOverweight - ); - weight_before_filtering }; // Note that `process_checked_multi_dispute_data` will iterate and import each @@ -567,98 +551,9 @@ impl Pallet { log::debug!(target: LOG_TARGET, "Evicted timed out cores: {:?}", freed_timeout); } - // We'll schedule paras again, given freed cores, and reasons for freeing. - let freed = freed_concluded - .into_iter() - .map(|(c, _hash)| (c, FreedReason::Concluded)) - .chain(freed_disputed.into_iter().map(|core| (core, FreedReason::Concluded))) - .chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut))) - .collect::>(); - scheduler::Pallet::::free_cores_and_fill_claim_queue(freed, now); - - METRICS.on_candidates_processed_total(backed_candidates.len() as u64); - - // After freeing cores and filling claims, but before processing backed candidates - // we update the allowed relay-parents. - { - let parent_number = now - One::one(); - let parent_storage_root = *parent_header.state_root(); - - shared::AllowedRelayParents::::mutate(|tracker| { - tracker.update( - parent_hash, - parent_storage_root, - scheduler::ClaimQueue::::get() - .into_iter() - .map(|(core_index, paras)| { - (core_index, paras.into_iter().map(|e| e.para_id()).collect()) - }) - .collect(), - parent_number, - config.async_backing_params.allowed_ancestry_len, - ); - }); - } - let allowed_relay_parents = shared::AllowedRelayParents::::get(); - - let core_index_enabled = configuration::ActiveConfig::::get() - .node_features - .get(FeatureIndex::ElasticScalingMVP as usize) - .map(|b| *b) - .unwrap_or(false); - - let allow_v2_receipts = configuration::ActiveConfig::::get() - .node_features - .get(FeatureIndex::CandidateReceiptV2 as usize) - .map(|b| *b) - .unwrap_or(false); - - let mut eligible: BTreeMap> = BTreeMap::new(); - let mut total_eligible_cores = 0; - - for (core_idx, para_id) in scheduler::Pallet::::eligible_paras() { - total_eligible_cores += 1; - log::trace!(target: LOG_TARGET, "Found eligible para {:?} on core {:?}", para_id, core_idx); - eligible.entry(para_id).or_default().insert(core_idx); - } - - let initial_candidate_count = backed_candidates.len(); - let backed_candidates_with_core = sanitize_backed_candidates::( - backed_candidates, - &allowed_relay_parents, - concluded_invalid_hashes, - eligible, - core_index_enabled, - allow_v2_receipts, - ); - let count = count_backed_candidates(&backed_candidates_with_core); - - ensure!(count <= total_eligible_cores, Error::::UnscheduledCandidate); - - METRICS.on_candidates_sanitized(count as u64); - - // In `Enter` context (invoked during execution) no more candidates should be filtered, - // because they have already been filtered during `ProvideInherent` context. Abort in such - // cases. - if context == ProcessInherentDataContext::Enter { - ensure!( - initial_candidate_count == count, - Error::::CandidatesFilteredDuringExecution - ); - } - - // Process backed candidates according to scheduled cores. - let inclusion::ProcessedCandidates::< as HeaderT>::Hash> { - core_indices: occupied, - candidate_receipt_with_backing_validator_indices, - } = inclusion::Pallet::::process_candidates( - &allowed_relay_parents, - &backed_candidates_with_core, - scheduler::Pallet::::group_validators, - core_index_enabled, - )?; - // Note which of the scheduled cores were actually occupied by a backed candidate. - scheduler::Pallet::::occupied(occupied.into_iter().map(|e| (e.0, e.1)).collect()); + // Back candidates. + let (candidate_receipt_with_backing_validator_indices, backed_candidates_with_core) = + Self::back_candidates(concluded_invalid_hashes, backed_candidates)?; set_scrapable_on_chain_backings::( current_session, @@ -672,6 +567,7 @@ impl Pallet { let bitfields = bitfields.into_iter().map(|v| v.into_unchecked()).collect(); + let count = backed_candidates_with_core.len(); let processed = ParachainsInherentData { bitfields, backed_candidates: backed_candidates_with_core.into_iter().fold( @@ -686,6 +582,104 @@ impl Pallet { }; Ok((processed, Some(all_weight_after).into())) } + + fn back_candidates( + concluded_invalid_hashes: BTreeSet, + backed_candidates: Vec>, + ) -> Result< + ( + Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, + BTreeMap, CoreIndex)>>, + ), + DispatchErrorWithPostInfo, + > { + let allowed_relay_parents = shared::AllowedRelayParents::::get(); + let upcoming_new_session = initializer::Pallet::::upcoming_session_change(); + + METRICS.on_candidates_processed_total(backed_candidates.len() as u64); + + if !upcoming_new_session { + let occupied_cores = + inclusion::Pallet::::get_occupied_cores().map(|(core, _)| core).collect(); + + let mut eligible: BTreeMap> = BTreeMap::new(); + let mut total_eligible_cores = 0; + + for (core_idx, para_id) in Self::eligible_paras(&occupied_cores) { + total_eligible_cores += 1; + log::trace!(target: LOG_TARGET, "Found eligible para {:?} on core {:?}", para_id, core_idx); + eligible.entry(para_id).or_default().insert(core_idx); + } + + let node_features = configuration::ActiveConfig::::get().node_features; + let core_index_enabled = node_features + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|b| *b) + .unwrap_or(false); + + let allow_v2_receipts = node_features + .get(FeatureIndex::CandidateReceiptV2 as usize) + .map(|b| *b) + .unwrap_or(false); + + let backed_candidates_with_core = sanitize_backed_candidates::( + backed_candidates, + &allowed_relay_parents, + concluded_invalid_hashes, + eligible, + core_index_enabled, + allow_v2_receipts, + ); + let count = count_backed_candidates(&backed_candidates_with_core); + + ensure!(count <= total_eligible_cores, Error::::UnscheduledCandidate); + + METRICS.on_candidates_sanitized(count as u64); + + // Process backed candidates according to scheduled cores. + let candidate_receipt_with_backing_validator_indices = + inclusion::Pallet::::process_candidates( + &allowed_relay_parents, + &backed_candidates_with_core, + scheduler::Pallet::::group_validators, + core_index_enabled, + )?; + + // We need to advance the claim queue on all cores, except for the ones that did not + // get freed in this block. The ones that did not get freed also cannot be newly + // occupied. + scheduler::Pallet::::advance_claim_queue(&occupied_cores); + + Ok((candidate_receipt_with_backing_validator_indices, backed_candidates_with_core)) + } else { + log::debug!( + target: LOG_TARGET, + "Upcoming session change, not backing any new candidates." + ); + // If we'll initialize a new session at the end of the block, we don't want to + // advance the claim queue. + + Ok((vec![], BTreeMap::new())) + } + } + + /// Paras that may get backed on cores. + /// + /// 1. The para must be scheduled on core. + /// 2. Core needs to be free, otherwise backing is not possible. + /// + /// We get a set of the occupied cores as input. + pub(crate) fn eligible_paras<'a>( + occupied_cores: &'a BTreeSet, + ) -> impl Iterator + 'a { + scheduler::ClaimQueue::::get().into_iter().filter_map(|(core_idx, queue)| { + if occupied_cores.contains(&core_idx) { + return None + } + let next_scheduled = queue.front()?; + Some((core_idx, next_scheduled.para_id())) + }) + } } /// Derive a bitfield from dispute @@ -1144,10 +1138,7 @@ fn sanitize_backed_candidates( } fn count_backed_candidates(backed_candidates: &BTreeMap>) -> usize { - backed_candidates.iter().fold(0, |mut count, (_id, candidates)| { - count += candidates.len(); - count - }) + backed_candidates.values().map(|c| c.len()).sum() } /// Derive entropy from babe provided per block randomness. diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index f5c3d5077764..146be0ee0aad 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -49,11 +49,10 @@ mod enter { use crate::{ builder::{junk_collator, junk_collator_signature, Bench, BenchBuilder, CandidateModifier}, + disputes::clear_dispute_storage, + initializer::BufferedSessionChange, mock::{mock_assigner, new_test_ext, BlockLength, BlockWeights, RuntimeOrigin, Test}, - scheduler::{ - common::{Assignment, AssignmentProvider}, - ParasEntry, - }, + scheduler::common::{Assignment, AssignmentProvider}, session_info, }; use alloc::collections::btree_map::BTreeMap; @@ -62,7 +61,9 @@ mod enter { use frame_support::assert_ok; use frame_system::limits; use polkadot_primitives::{ - vstaging::{CandidateDescriptorV2, CommittedCandidateReceiptV2, InternalVersion}, + vstaging::{ + CandidateDescriptorV2, CommittedCandidateReceiptV2, InternalVersion, MutateDescriptorV2, + }, AvailabilityBitfield, CandidateDescriptor, UncheckedSigned, }; use sp_runtime::Perbill; @@ -73,7 +74,6 @@ mod enter { backed_and_concluding: BTreeMap, num_validators_per_core: u32, code_upgrade: Option, - fill_claimqueue: bool, elastic_paras: BTreeMap, unavailable_cores: Vec, v2_descriptor: bool, @@ -87,7 +87,6 @@ mod enter { backed_and_concluding, num_validators_per_core, code_upgrade, - fill_claimqueue, elastic_paras, unavailable_cores, v2_descriptor, @@ -108,14 +107,11 @@ mod enter { .set_dispute_statements(dispute_statements) .set_backed_and_concluding_paras(backed_and_concluding.clone()) .set_dispute_sessions(&dispute_sessions[..]) - .set_fill_claimqueue(fill_claimqueue) .set_unavailable_cores(unavailable_cores) .set_candidate_descriptor_v2(v2_descriptor) .set_candidate_modifier(candidate_modifier); // Setup some assignments as needed: - mock_assigner::Pallet::::set_core_count(builder.max_cores()); - (0..(builder.max_cores() as usize - extra_cores)).for_each(|para_id| { (0..elastic_paras.get(&(para_id as u32)).cloned().unwrap_or(1)).for_each( |_para_local_core_idx| { @@ -164,7 +160,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor, @@ -188,6 +183,7 @@ mod enter { inherent_data .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); // Nothing is filtered out (including the backed candidates.) assert_eq!( @@ -272,7 +268,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 3)].into_iter().collect(), unavailable_cores: vec![], v2_descriptor, @@ -293,6 +288,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); assert!(pallet::OnChainVotes::::get().is_none()); // Nothing is filtered out (including the backed candidates.) @@ -375,7 +371,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 4)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), v2_descriptor: false, @@ -527,6 +522,101 @@ mod enter { }); } + #[test] + // Test that no new candidates are backed if there's an upcoming session change scheduled at the + // end of the block. Claim queue will also not be advanced. + fn session_change() { + let config = MockGenesisConfig::default(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + + new_test_ext(config).execute_with(|| { + let dispute_statements = BTreeMap::new(); + + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + + let scenario = make_inherent_data(TestConfig { + dispute_statements, + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, + }); + + let prev_claim_queue = scheduler::ClaimQueue::::get(); + + assert_eq!(inclusion::PendingAvailability::::iter().count(), 2); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(0)).unwrap().len(), + 1 + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(1)).unwrap().len(), + 1 + ); + + // We expect the scenario to have cores 0 & 1 with pending availability. The backed + // candidates are also created for cores 0 & 1. The pending available candidates will + // become available but the new candidates will not be backed since there is an upcoming + // session change. + let mut expected_para_inherent_data = scenario.data.clone(); + expected_para_inherent_data.backed_candidates.clear(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (2 validators) + assert_eq!(expected_para_inherent_data.bitfields.len(), 2); + // * 0 disputes. + assert_eq!(expected_para_inherent_data.disputes.len(), 0); + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) + .unwrap(); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); + + // Simulate a session change scheduled to happen at the end of the block. + initializer::BufferedSessionChanges::::put(vec![BufferedSessionChange { + validators: vec![], + queued: vec![], + session_index: 3, + }]); + + // Only backed candidates are filtered out. + assert_eq!( + Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(), + expected_para_inherent_data + ); + + assert_eq!( + // No candidates backed. + OnChainVotes::::get().unwrap().backing_validators_per_candidate.len(), + 0 + ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + OnChainVotes::::get().unwrap().session, + 2 + ); + + // No pending availability candidates. + assert_eq!(inclusion::PendingAvailability::::iter().count(), 2); + assert!(inclusion::PendingAvailability::::get(ParaId::from(0)) + .unwrap() + .is_empty()); + assert!(inclusion::PendingAvailability::::get(ParaId::from(1)) + .unwrap() + .is_empty()); + + // The claim queue should not have been advanced. + assert_eq!(prev_claim_queue, scheduler::ClaimQueue::::get()); + }); + } + #[test] fn test_session_is_tracked_in_on_chain_scraping() { use crate::disputes::run_to_block; @@ -633,7 +723,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -655,8 +744,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); let multi_dispute_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); @@ -671,6 +759,8 @@ mod enter { &expected_para_inherent_data.disputes[..2], ); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), multi_dispute_inherent_data, @@ -708,7 +798,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 6, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -729,8 +818,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); @@ -742,6 +830,8 @@ mod enter { assert_eq!(limit_inherent_data.disputes[0].session, 1); assert_eq!(limit_inherent_data.disputes[1].session, 2); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -781,7 +871,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 4, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -803,8 +892,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); // Nothing is filtered out (including the backed candidates.) let limit_inherent_data = @@ -826,6 +914,8 @@ mod enter { // over weight assert_eq!(limit_inherent_data.backed_candidates.len(), 0); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -870,7 +960,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -892,10 +981,8 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); - // Nothing is filtered out (including the backed candidates.) let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); assert_ne!(limit_inherent_data, expected_para_inherent_data); @@ -916,9 +1003,11 @@ mod enter { // over weight assert_eq!(limit_inherent_data.backed_candidates.len(), 0); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), - limit_inherent_data, + limit_inherent_data )); assert_eq!( @@ -959,7 +1048,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1020,7 +1108,6 @@ mod enter { backed_and_concluding, num_validators_per_core, code_upgrade: None, - fill_claimqueue: true, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1043,6 +1130,21 @@ mod enter { Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); assert!(limit_inherent_data == expected_para_inherent_data); + // Cores were scheduled. We should put the assignments back, before calling enter(). + let cores = (0..num_candidates) + .into_iter() + .map(|i| { + // Load an assignment into provider so that one is present to pop + let assignment = + ::AssignmentProvider::get_mock_assignment( + CoreIndex(i), + ParaId::from(i), + ); + (CoreIndex(i), [assignment].into()) + }) + .collect(); + scheduler::ClaimQueue::::set(cores); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -1108,7 +1210,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1166,24 +1267,23 @@ mod enter { ); // One core was scheduled. We should put the assignment back, before calling enter(). - let now = frame_system::Pallet::::block_number() + 1; let used_cores = 5; let cores = (0..used_cores) .into_iter() .map(|i| { - let SchedulerParams { ttl, .. } = - configuration::ActiveConfig::::get().scheduler_params; // Load an assignment into provider so that one is present to pop let assignment = ::AssignmentProvider::get_mock_assignment( CoreIndex(i), ParaId::from(i), ); - (CoreIndex(i), [ParasEntry::new(assignment, now + ttl)].into()) + (CoreIndex(i), [assignment].into()) }) .collect(); scheduler::ClaimQueue::::set(cores); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -1217,7 +1317,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1287,7 +1386,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1355,7 +1453,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1446,7 +1543,6 @@ mod enter { } // Ensure that overweight parachain inherents are always rejected by the runtime. - // Runtime should panic and return `InherentOverweight` error. #[rstest] #[case(true)] #[case(false)] @@ -1479,7 +1575,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor, @@ -1548,7 +1643,6 @@ mod enter { } // Ensure that overweight parachain inherents are always rejected by the runtime. - // Runtime should panic and return `InherentOverweight` error. #[test] fn inherent_create_weight_invariant() { new_test_ext(MockGenesisConfig::default()).execute_with(|| { @@ -1570,7 +1664,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], v2_descriptor: false, @@ -1600,7 +1693,7 @@ mod enter { .unwrap_err() .error; - assert_eq!(dispatch_error, Error::::InherentOverweight.into()); + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); }); } @@ -1630,7 +1723,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 8)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), v2_descriptor: true, @@ -1670,7 +1762,7 @@ mod enter { // We expect `enter` to fail because the inherent data contains backed candidates with // v2 descriptors. - assert_eq!(dispatch_error, Error::::CandidatesFilteredDuringExecution.into()); + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); }); } @@ -1698,9 +1790,8 @@ mod enter { dispute_statements: BTreeMap::new(), dispute_sessions: vec![], // No disputes backed_and_concluding, - num_validators_per_core: 5, + num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 8)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), v2_descriptor: true, @@ -1719,8 +1810,8 @@ mod enter { let unfiltered_para_inherent_data = scenario.data.clone(); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 10 backed candidates) - assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 50); + // * 1 bitfield per validator (1 validators per core, 10 backed candidates) + assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 10); // * 10 v2 candidate descriptors. assert_eq!(unfiltered_para_inherent_data.backed_candidates.len(), 10); @@ -1738,7 +1829,7 @@ mod enter { // We expect `enter` to fail because the inherent data contains backed candidates with // v2 descriptors. - assert_eq!(dispatch_error, Error::::CandidatesFilteredDuringExecution.into()); + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); }); } @@ -1766,19 +1857,15 @@ mod enter { dispute_statements: BTreeMap::new(), dispute_sessions: vec![], // No disputes backed_and_concluding, - num_validators_per_core: 5, + num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 8)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), 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 }), @@ -1787,8 +1874,8 @@ mod enter { let unfiltered_para_inherent_data = scenario.data.clone(); // Check the para inherent data is as expected: - // * 1 bitfield per validator (5 validators per core, 10 backed candidates) - assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 50); + // * 1 bitfield per validator (1 validator per core, 10 backed candidates) + assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 10); // * 10 v2 candidate descriptors. assert_eq!(unfiltered_para_inherent_data.backed_candidates.len(), 10); @@ -1806,7 +1893,7 @@ mod enter { // We expect `enter` to fail because the inherent data contains backed candidates with // v2 descriptors. - assert_eq!(dispatch_error, Error::::CandidatesFilteredDuringExecution.into()); + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); }); } #[test] @@ -1843,7 +1930,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 3)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), v2_descriptor: true, @@ -1898,7 +1984,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 3)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), v2_descriptor: true, @@ -1985,7 +2070,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: Default::default(), unavailable_cores: unavailable_cores.clone(), v2_descriptor: true, @@ -2040,7 +2124,6 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 3)].into_iter().collect(), unavailable_cores, v2_descriptor: true, @@ -2372,7 +2455,7 @@ mod sanitizers { mod candidates { use crate::{ mock::{set_disabled_validators, RuntimeOrigin}, - scheduler::{common::Assignment, ParasEntry}, + scheduler::common::Assignment, util::{make_persisted_validation_data, make_persisted_validation_data_with_parent}, }; use alloc::collections::vec_deque::VecDeque; @@ -2453,17 +2536,17 @@ mod sanitizers { scheduler::Pallet::::set_claim_queue(BTreeMap::from([ ( CoreIndex::from(0), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), ), ( CoreIndex::from(1), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(1), + }]), ), ])); @@ -2545,7 +2628,7 @@ mod sanitizers { // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), + Pallet::::eligible_paras(&Default::default()).collect::>(), vec![(CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(2))] ); assert_eq!( @@ -2641,73 +2724,73 @@ mod sanitizers { scheduler::Pallet::::set_claim_queue(BTreeMap::from([ ( CoreIndex::from(0), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), ), ( CoreIndex::from(1), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(1), + }]), ), ( CoreIndex::from(2), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(2) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(2), + }]), ), ( CoreIndex::from(3), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(3), + }]), ), ( CoreIndex::from(4), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(4) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 3.into(), + core_index: CoreIndex(4), + }]), ), ( CoreIndex::from(5), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(5) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 4.into(), + core_index: CoreIndex(5), + }]), ), ( CoreIndex::from(6), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 5.into(), core_index: CoreIndex(6) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 5.into(), + core_index: CoreIndex(6), + }]), ), ( CoreIndex::from(7), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 7.into(), core_index: CoreIndex(7) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 7.into(), + core_index: CoreIndex(7), + }]), ), ( CoreIndex::from(8), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 7.into(), core_index: CoreIndex(8) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 7.into(), + core_index: CoreIndex(8), + }]), ), ( CoreIndex::from(9), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 8.into(), core_index: CoreIndex(9) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 8.into(), + core_index: CoreIndex(9), + }]), ), ])); @@ -3087,7 +3170,7 @@ mod sanitizers { // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), + Pallet::::eligible_paras(&Default::default()).collect::>(), vec![ (CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(1)), @@ -3102,7 +3185,7 @@ mod sanitizers { ] ); let mut scheduled: BTreeMap> = BTreeMap::new(); - for (core_idx, para_id) in scheduler::Pallet::::scheduled_paras() { + for (core_idx, para_id) in Pallet::::eligible_paras(&Default::default()) { scheduled.entry(para_id).or_default().insert(core_idx); } @@ -3186,66 +3269,66 @@ mod sanitizers { scheduler::Pallet::::set_claim_queue(BTreeMap::from([ ( CoreIndex::from(0), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), ), ( CoreIndex::from(1), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(1), + }]), ), ( CoreIndex::from(2), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(2) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(2), + }]), ), ( CoreIndex::from(3), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(3), + }]), ), ( CoreIndex::from(4), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(4) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(4), + }]), ), ( CoreIndex::from(5), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(5) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 3.into(), + core_index: CoreIndex(5), + }]), ), ( CoreIndex::from(6), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(6) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 3.into(), + core_index: CoreIndex(6), + }]), ), ( CoreIndex::from(7), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(7) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 4.into(), + core_index: CoreIndex(7), + }]), ), ( CoreIndex::from(8), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(8) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 4.into(), + core_index: CoreIndex(8), + }]), ), ])); @@ -3575,7 +3658,7 @@ mod sanitizers { // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), + Pallet::::eligible_paras(&Default::default()).collect::>(), vec![ (CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(1)), @@ -3589,7 +3672,7 @@ mod sanitizers { ] ); let mut scheduled: BTreeMap> = BTreeMap::new(); - for (core_idx, para_id) in scheduler::Pallet::::scheduled_paras() { + for (core_idx, para_id) in Pallet::::eligible_paras(&Default::default()) { scheduled.entry(para_id).or_default().insert(core_idx); } @@ -3710,45 +3793,45 @@ mod sanitizers { scheduler::Pallet::::set_claim_queue(BTreeMap::from([ ( CoreIndex::from(0), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(0) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), ), ( CoreIndex::from(1), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(1), + }]), ), ( CoreIndex::from(2), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(2) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(2), + }]), ), ( CoreIndex::from(3), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(3), + }]), ), ( CoreIndex::from(4), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(4) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(4), + }]), ), ( CoreIndex::from(5), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(5) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(5), + }]), ), ])); @@ -3996,7 +4079,7 @@ mod sanitizers { // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), + Pallet::::eligible_paras(&Default::default()).collect::>(), vec![ (CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(1)), @@ -4007,7 +4090,7 @@ mod sanitizers { ] ); let mut scheduled: BTreeMap> = BTreeMap::new(); - for (core_idx, para_id) in scheduler::Pallet::::scheduled_paras() { + for (core_idx, para_id) in Pallet::::eligible_paras(&Default::default()) { scheduled.entry(para_id).or_default().insert(core_idx); } diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs index a0996d5df0ee..e9327bc7641a 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs @@ -18,8 +18,7 @@ //! functions. use crate::{ - configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, - scheduler::{self, CoreOccupied}, + configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler, session_info, shared, }; use alloc::{ @@ -67,15 +66,6 @@ pub fn validator_groups( /// Implementation for the `availability_cores` function of the runtime API. pub fn availability_cores() -> Vec>> { - let cores = scheduler::AvailabilityCores::::get(); - let now = frame_system::Pallet::::block_number() + One::one(); - - // This explicit update is only strictly required for session boundaries: - // - // At the end of a session we clear the claim queues: Without this update call, nothing would be - // scheduled to the client. - scheduler::Pallet::::free_cores_and_fill_claim_queue(Vec::new(), now); - let time_out_for = scheduler::Pallet::::availability_timeout_predicate(); let group_responsible_for = @@ -95,76 +85,42 @@ pub fn availability_cores() -> Vec = scheduler::Pallet::::scheduled_paras().collect(); - - cores - .into_iter() - .enumerate() - .map(|(i, core)| match core { - CoreOccupied::Paras(entry) => { - // Due to https://github.com/paritytech/polkadot-sdk/issues/64, using the new storage types would cause - // this runtime API to panic. We explicitly handle the storage for version 0 to - // prevent that. When removing the inclusion v0 -> v1 migration, this bit of code - // can also be removed. - let pending_availability = if inclusion::Pallet::::on_chain_storage_version() == - StorageVersion::new(0) - { - inclusion::migration::v0::PendingAvailability::::get(entry.para_id()) - .expect("Occupied core always has pending availability; qed") - } else { - let candidate = inclusion::Pallet::::pending_availability_with_core( - entry.para_id(), - CoreIndex(i as u32), - ) - .expect("Occupied core always has pending availability; qed"); - - // Translate to the old candidate format, as we don't need the commitments now. - inclusion::migration::v0::CandidatePendingAvailability { - core: candidate.core_occupied(), - hash: candidate.candidate_hash(), - descriptor: candidate.candidate_descriptor().clone(), - availability_votes: candidate.availability_votes().clone(), - backers: candidate.backers().clone(), - relay_parent_number: candidate.relay_parent_number(), - backed_in_number: candidate.backed_in_number(), - backing_group: candidate.backing_group(), - } - }; - - let backed_in_number = pending_availability.backed_in_number; + let claim_queue = scheduler::Pallet::::get_claim_queue(); + let occupied_cores: BTreeMap> = + inclusion::Pallet::::get_occupied_cores().collect(); + let n_cores = scheduler::Pallet::::num_availability_cores(); + (0..n_cores) + .map(|core_idx| { + let core_idx = CoreIndex(core_idx as u32); + if let Some(pending_availability) = occupied_cores.get(&core_idx) { // Use the same block number for determining the responsible group as what the // backing subsystem would use when it calls validator_groups api. let backing_group_allocation_time = - pending_availability.relay_parent_number + One::one(); + pending_availability.relay_parent_number() + One::one(); CoreState::Occupied(OccupiedCore { - next_up_on_available: scheduler::Pallet::::next_up_on_available(CoreIndex( - i as u32, - )), - occupied_since: backed_in_number, - time_out_at: time_out_for(backed_in_number).live_until, - next_up_on_time_out: scheduler::Pallet::::next_up_on_time_out(CoreIndex( - i as u32, - )), - availability: pending_availability.availability_votes.clone(), + next_up_on_available: scheduler::Pallet::::next_up_on_available(core_idx), + occupied_since: pending_availability.backed_in_number(), + time_out_at: time_out_for(pending_availability.backed_in_number()).live_until, + next_up_on_time_out: scheduler::Pallet::::next_up_on_available(core_idx), + availability: pending_availability.availability_votes().clone(), group_responsible: group_responsible_for( backing_group_allocation_time, - pending_availability.core, + pending_availability.core_occupied(), ), - candidate_hash: pending_availability.hash, - candidate_descriptor: pending_availability.descriptor, + candidate_hash: pending_availability.candidate_hash(), + candidate_descriptor: pending_availability.candidate_descriptor().clone(), }) - }, - CoreOccupied::Free => { - if let Some(para_id) = scheduled.get(&CoreIndex(i as _)).cloned() { + } else { + if let Some(assignment) = claim_queue.get(&core_idx).and_then(|q| q.front()) { CoreState::Scheduled(polkadot_primitives::ScheduledCore { - para_id, + para_id: assignment.para_id(), collator: None, }) } else { CoreState::Free } - }, + } }) .collect() } @@ -195,13 +151,12 @@ where build() }, OccupiedCoreAssumption::TimedOut => build(), - OccupiedCoreAssumption::Free => { - if >::pending_availability(para_id).is_some() { + OccupiedCoreAssumption::Free => + if !>::candidates_pending_availability(para_id).is_empty() { None } else { build() - } - }, + }, } } @@ -240,10 +195,12 @@ pub fn assumed_validation_data( let persisted_validation_data = make_validation_data().or_else(|| { // Try again with force enacting the pending candidates. This check only makes sense if // there are any pending candidates. - inclusion::Pallet::::pending_availability(para_id).and_then(|_| { - inclusion::Pallet::::force_enact(para_id); - make_validation_data() - }) + (!inclusion::Pallet::::candidates_pending_availability(para_id).is_empty()) + .then_some(()) + .and_then(|_| { + inclusion::Pallet::::force_enact(para_id); + make_validation_data() + }) }); // If we were successful, also query current validation code hash. persisted_validation_data.zip(paras::CurrentCodeHash::::get(¶_id)) @@ -319,7 +276,7 @@ pub fn validation_code( pub fn candidate_pending_availability( para_id: ParaId, ) -> Option> { - inclusion::Pallet::::candidate_pending_availability(para_id) + inclusion::Pallet::::first_candidate_pending_availability(para_id) } /// Implementation for the `candidate_events` function of the runtime API. @@ -568,23 +525,12 @@ pub fn approval_voting_params() -> ApprovalVotingParams /// Returns the claimqueue from the scheduler pub fn claim_queue() -> BTreeMap> { - let now = >::block_number() + One::one(); - - // This is needed so that the claim queue always has the right size (equal to - // scheduling_lookahead). Otherwise, if a candidate is backed in the same block where the - // previous candidate is included, the claim queue will have already pop()-ed the next item - // from the queue and the length would be `scheduling_lookahead - 1`. - >::free_cores_and_fill_claim_queue(Vec::new(), now); let config = configuration::ActiveConfig::::get(); // Extra sanity, config should already never be smaller than 1: let n_lookahead = config.scheduler_params.lookahead.max(1); - - scheduler::ClaimQueue::::get() + scheduler::Pallet::::get_claim_queue() .into_iter() .map(|(core_index, entries)| { - // on cores timing out internal claim queue size may be temporarily longer than it - // should be as the timed out assignment might got pushed back to an already full claim - // queue: ( core_index, entries.into_iter().map(|e| e.para_id()).take(n_lookahead as usize).collect(), diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 445583d929ab..9c111c2d28e7 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -36,21 +36,17 @@ //! number of groups as availability cores. Validator groups will be assigned to different //! availability cores over time. -use core::iter::Peekable; - use crate::{configuration, initializer::SessionChangeNotification, paras}; use alloc::{ - collections::{ - btree_map::{self, BTreeMap}, - vec_deque::VecDeque, - }, + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, vec::Vec, }; 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; @@ -71,7 +67,7 @@ pub mod migration; pub mod pallet { use super::*; - const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); #[pallet::pallet] #[pallet::without_storage_info] @@ -93,47 +89,6 @@ pub mod pallet { #[pallet::storage] pub type ValidatorGroups = StorageValue<_, Vec>, ValueQuery>; - /// One entry for each availability core. The i'th parachain belongs to the i'th core, with the - /// remaining cores all being on demand parachain multiplexers. - /// - /// Bounded by the maximum of either of these two values: - /// * The number of parachains and parathread multiplexers - /// * The number of validators divided by `configuration.max_validators_per_core`. - #[pallet::storage] - pub type AvailabilityCores = StorageValue<_, Vec>, ValueQuery>; - - /// Representation of a core in `AvailabilityCores`. - /// - /// This is not to be confused with `CoreState` which is an enriched variant of this and exposed - /// to the node side. It also provides information about scheduled/upcoming assignments for - /// example and is computed on the fly in the `availability_cores` runtime call. - #[derive(Encode, Decode, TypeInfo, RuntimeDebug, PartialEq)] - pub enum CoreOccupied { - /// No candidate is waiting availability on this core right now (the core is not occupied). - Free, - /// A para is currently waiting for availability/inclusion on this core. - Paras(ParasEntry), - } - - /// Convenience type alias for `CoreOccupied`. - pub type CoreOccupiedType = CoreOccupied>; - - impl CoreOccupied { - /// Is core free? - pub fn is_free(&self) -> bool { - matches!(self, Self::Free) - } - } - - /// Reasons a core might be freed. - #[derive(Clone, Copy)] - pub enum FreedReason { - /// The core's work concluded and the parablock assigned to it is considered available. - Concluded, - /// The core's work timed out. - TimedOut, - } - /// The block number where the session start occurred. Used to track how many group rotations /// have occurred. /// @@ -145,40 +100,9 @@ pub mod pallet { pub type SessionStartBlock = StorageValue<_, BlockNumberFor, ValueQuery>; /// One entry for each availability core. The `VecDeque` represents the assignments to be - /// scheduled on that core. The value contained here will not be valid after the end of - /// a block. Runtime APIs should be used to determine scheduled cores for the upcoming block. + /// scheduled on that core. #[pallet::storage] - pub type ClaimQueue = - StorageValue<_, BTreeMap>>, ValueQuery>; - - /// Assignments as tracked in the claim queue. - #[derive(Encode, Decode, TypeInfo, RuntimeDebug, PartialEq, Clone)] - pub struct ParasEntry { - /// The underlying [`Assignment`]. - pub assignment: Assignment, - /// The number of times the entry has timed out in availability already. - pub availability_timeouts: u32, - /// The block height until this entry needs to be backed. - /// - /// If missed the entry will be removed from the claim queue without ever having occupied - /// the core. - pub ttl: N, - } - - /// Convenience type declaration for `ParasEntry`. - pub type ParasEntryType = ParasEntry>; - - impl ParasEntry { - /// Create a new `ParasEntry`. - pub fn new(assignment: Assignment, now: N) -> Self { - ParasEntry { assignment, availability_timeouts: 0, ttl: now } - } - - /// Return `Id` from the underlying `Assignment`. - pub fn para_id(&self) -> ParaId { - self.assignment.para_id() - } - } + pub type ClaimQueue = StorageValue<_, BTreeMap>, ValueQuery>; /// Availability timeout status of a core. pub(crate) struct AvailabilityTimeoutStatus { @@ -195,30 +119,6 @@ pub mod pallet { } } -type PositionInClaimQueue = u32; - -struct ClaimQueueIterator { - next_idx: u32, - queue: Peekable>>, -} - -impl Iterator for ClaimQueueIterator { - type Item = (CoreIndex, VecDeque); - - fn next(&mut self) -> Option { - let (idx, _) = self.queue.peek()?; - let val = if idx != &CoreIndex(self.next_idx) { - log::trace!(target: LOG_TARGET, "idx did not match claim queue idx: {:?} vs {:?}", idx, self.next_idx); - (CoreIndex(self.next_idx), VecDeque::new()) - } else { - let (idx, q) = self.queue.next()?; - (idx, q) - }; - self.next_idx += 1; - Some(val) - } -} - impl Pallet { /// Called by the initializer to initialize the scheduler pallet. pub(crate) fn initializer_initialize(_now: BlockNumberFor) -> Weight { @@ -228,31 +128,22 @@ impl Pallet { /// Called by the initializer to finalize the scheduler pallet. pub(crate) fn initializer_finalize() {} - /// Called before the initializer notifies of a new session. - pub(crate) fn pre_new_session() { - Self::push_claim_queue_items_to_assignment_provider(); - Self::push_occupied_cores_to_assignment_provider(); - } - /// Called by the initializer to note that a new session has started. pub(crate) fn initializer_on_new_session( notification: &SessionChangeNotification>, ) { let SessionChangeNotification { validators, new_config, .. } = notification; let config = new_config; + let assigner_cores = config.scheduler_params.num_cores; let n_cores = core::cmp::max( - T::AssignmentProvider::session_core_count(), + assigner_cores, match config.scheduler_params.max_validators_per_core { Some(x) if x != 0 => validators.len() as u32 / x, _ => 0, }, ); - AvailabilityCores::::mutate(|cores| { - cores.resize_with(n_cores as _, || CoreOccupied::Free); - }); - // shuffle validators into groups. if n_cores == 0 || validators.is_empty() { ValidatorGroups::::set(Vec::new()); @@ -295,149 +186,28 @@ impl Pallet { ValidatorGroups::::set(groups); } + // Resize and populate claim queue. + Self::maybe_resize_claim_queue(); + Self::populate_claim_queue_after_session_change(); + let now = frame_system::Pallet::::block_number() + One::one(); SessionStartBlock::::set(now); } - /// Free unassigned cores. Provide a list of cores that should be considered newly-freed along - /// with the reason for them being freed. Returns a tuple of concluded and timedout paras. - fn free_cores( - just_freed_cores: impl IntoIterator, - ) -> (BTreeMap, BTreeMap>) { - let mut timedout_paras: BTreeMap> = BTreeMap::new(); - let mut concluded_paras = BTreeMap::new(); - - AvailabilityCores::::mutate(|cores| { - let c_len = cores.len(); - - just_freed_cores - .into_iter() - .filter(|(freed_index, _)| (freed_index.0 as usize) < c_len) - .for_each(|(freed_index, freed_reason)| { - match core::mem::replace(&mut cores[freed_index.0 as usize], CoreOccupied::Free) - { - CoreOccupied::Free => {}, - CoreOccupied::Paras(entry) => { - match freed_reason { - FreedReason::Concluded => { - concluded_paras.insert(freed_index, entry.assignment); - }, - FreedReason::TimedOut => { - timedout_paras.insert(freed_index, entry); - }, - }; - }, - }; - }) - }); - - (concluded_paras, timedout_paras) - } - - /// Get an iterator into the claim queues. - /// - /// This iterator will have an item for each and every core index up to the maximum core index - /// found in the claim queue. In other words there will be no holes/missing core indices, - /// between core 0 and the maximum, even if the claim queue was missing entries for particular - /// indices in between. (The iterator will return an empty `VecDeque` for those indices. - fn claim_queue_iterator() -> impl Iterator>)> { - let queues = ClaimQueue::::get(); - return ClaimQueueIterator::> { - next_idx: 0, - queue: queues.into_iter().peekable(), - } + /// Get the validators in the given group, if the group index is valid for this session. + pub(crate) fn group_validators(group_index: GroupIndex) -> Option> { + ValidatorGroups::::get().get(group_index.0 as usize).map(|g| g.clone()) } - /// Note that the given cores have become occupied. Update the claim queue accordingly. - /// This will not push a new entry onto the claim queue, so the length after this call will be - /// the expected length - 1. The claim_queue runtime API will take care of adding another entry - /// here, to ensure the right lookahead. - pub(crate) fn occupied( - now_occupied: BTreeMap, - ) -> BTreeMap { - let mut availability_cores = AvailabilityCores::::get(); - - log::debug!(target: LOG_TARGET, "[occupied] now_occupied {:?}", now_occupied); - - let pos_mapping: BTreeMap = now_occupied - .iter() - .flat_map(|(core_idx, para_id)| { - match Self::remove_from_claim_queue(*core_idx, *para_id) { - Err(e) => { - log::debug!( - target: LOG_TARGET, - "[occupied] error on remove_from_claim queue {}", - e - ); - None - }, - Ok((pos_in_claim_queue, pe)) => { - availability_cores[core_idx.0 as usize] = CoreOccupied::Paras(pe); - - Some((*core_idx, pos_in_claim_queue)) - }, - } - }) - .collect(); - - // Drop expired claims after processing now_occupied. - Self::drop_expired_claims_from_claim_queue(); - - AvailabilityCores::::set(availability_cores); - - pos_mapping + /// Get the number of cores. + pub(crate) fn num_availability_cores() -> usize { + ValidatorGroups::::decode_len().unwrap_or(0) } - /// Iterates through every element in all claim queues and tries to add new assignments from the - /// `AssignmentProvider`. A claim is considered expired if it's `ttl` field is lower than the - /// current block height. - fn drop_expired_claims_from_claim_queue() { - let now = frame_system::Pallet::::block_number(); - let availability_cores = AvailabilityCores::::get(); - let ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - - ClaimQueue::::mutate(|cq| { - for (idx, _) in (0u32..).zip(availability_cores) { - let core_idx = CoreIndex(idx); - if let Some(core_claim_queue) = cq.get_mut(&core_idx) { - let mut i = 0; - let mut num_dropped = 0; - while i < core_claim_queue.len() { - let maybe_dropped = if let Some(entry) = core_claim_queue.get(i) { - if entry.ttl < now { - core_claim_queue.remove(i) - } else { - None - } - } else { - None - }; - - if let Some(dropped) = maybe_dropped { - num_dropped += 1; - T::AssignmentProvider::report_processed(dropped.assignment); - } else { - i += 1; - } - } - - for _ in 0..num_dropped { - // For all claims dropped due to TTL, attempt to pop a new entry to - // the back of the claim queue. - if let Some(assignment) = - T::AssignmentProvider::pop_assignment_for_core(core_idx) - { - core_claim_queue.push_back(ParasEntry::new(assignment, now + ttl)); - } - } - } - } - }); - } - - /// Get the validators in the given group, if the group index is valid for this session. - pub(crate) fn group_validators(group_index: GroupIndex) -> Option> { - ValidatorGroups::::get().get(group_index.0 as usize).map(|g| g.clone()) + /// 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 @@ -531,183 +301,140 @@ impl Pallet { /// Return the next thing that will be scheduled on this core assuming it is currently /// occupied and the candidate occupying it became available. pub(crate) fn next_up_on_available(core: CoreIndex) -> Option { - ClaimQueue::::get() - .get(&core) - .and_then(|a| a.front().map(|pe| Self::paras_entry_to_scheduled_core(pe))) + // Since this is being called from a runtime API, we need to workaround for #64. + if Self::on_chain_storage_version() == StorageVersion::new(2) { + migration::v2::ClaimQueue::::get() + .get(&core) + .and_then(|a| a.front().map(|entry| entry.assignment.para_id())) + } else { + ClaimQueue::::get() + .get(&core) + .and_then(|a| a.front().map(|assignment| assignment.para_id())) + } + .map(|para_id| ScheduledCore { para_id, collator: None }) } - fn paras_entry_to_scheduled_core(pe: &ParasEntryType) -> ScheduledCore { - ScheduledCore { para_id: pe.para_id(), collator: None } + // Since this is being called from a runtime API, we need to workaround for #64. + pub(crate) fn get_claim_queue() -> BTreeMap> { + if Self::on_chain_storage_version() == StorageVersion::new(2) { + migration::v2::ClaimQueue::::get() + .into_iter() + .map(|(core_index, entries)| { + (core_index, entries.into_iter().map(|e| e.assignment).collect()) + }) + .collect() + } else { + ClaimQueue::::get() + } } - /// Return the next thing that will be scheduled on this core assuming it is currently - /// occupied and the candidate occupying it times out. - pub(crate) fn next_up_on_time_out(core: CoreIndex) -> Option { - let max_availability_timeouts = configuration::ActiveConfig::::get() - .scheduler_params - .max_availability_timeouts; - Self::next_up_on_available(core).or_else(|| { - // Or, if none, the claim currently occupying the core, - // as it would be put back on the queue after timing out if number of retries is not at - // the maximum. - let cores = AvailabilityCores::::get(); - cores.get(core.0 as usize).and_then(|c| match c { - CoreOccupied::Free => None, - CoreOccupied::Paras(pe) => - if pe.availability_timeouts < max_availability_timeouts { - Some(Self::paras_entry_to_scheduled_core(pe)) - } else { - None - }, - }) - }) - } + /// For each core that isn't part of the `except_for` set, pop the first item of the claim queue + /// and fill the queue from the assignment provider. + pub(crate) fn advance_claim_queue(except_for: &BTreeSet) { + let config = configuration::ActiveConfig::::get(); + 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..expected_claim_queue_len { + let core_idx = CoreIndex::from(core_idx); + + if !except_for.contains(&core_idx) { + let core_idx = CoreIndex::from(core_idx); - /// Pushes occupied cores to the assignment provider. - fn push_occupied_cores_to_assignment_provider() { - AvailabilityCores::::mutate(|cores| { - for core in cores.iter_mut() { - match core::mem::replace(core, CoreOccupied::Free) { - CoreOccupied::Free => continue, - CoreOccupied::Paras(entry) => { - Self::maybe_push_assignment(entry); - }, + if let Some(dropped_para) = Self::pop_front_of_claim_queue(&core_idx) { + T::AssignmentProvider::report_processed(dropped_para); } - } - }); - } - // on new session - fn push_claim_queue_items_to_assignment_provider() { - for (_, claim_queue) in ClaimQueue::::take() { - // Push back in reverse order so that when we pop from the provider again, - // the entries in the claim queue are in the same order as they are right now. - for para_entry in claim_queue.into_iter().rev() { - Self::maybe_push_assignment(para_entry); + Self::fill_claim_queue(core_idx, n_lookahead); } } } - /// Push assignments back to the provider on session change unless the paras - /// timed out on availability before. - fn maybe_push_assignment(pe: ParasEntryType) { - if pe.availability_timeouts == 0 { - T::AssignmentProvider::push_back_assignment(pe.assignment); + // on new session + 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)..=*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()); + } + } + }); } } - /// Frees cores and fills the free claim queue spots by popping from the `AssignmentProvider`. - pub fn free_cores_and_fill_claim_queue( - just_freed_cores: impl IntoIterator, - now: BlockNumberFor, - ) { - let (mut concluded_paras, mut timedout_paras) = Self::free_cores(just_freed_cores); - - // This can only happen on new sessions at which we move all assignments back to the - // provider. Hence, there's nothing we need to do here. - if ValidatorGroups::::decode_len().map_or(true, |l| l == 0) { - return - } - let n_session_cores = T::AssignmentProvider::session_core_count(); - let cq = ClaimQueue::::get(); + // Populate the claim queue. To be called on new session, after all the other modules were + // initialized. + fn populate_claim_queue_after_session_change() { 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 max_availability_timeouts = config.scheduler_params.max_availability_timeouts; - let ttl = config.scheduler_params.ttl; + let expected_claim_queue_len = Self::expected_claim_queue_len(&config.scheduler_params); - for core_idx in 0..n_session_cores { + for core_idx in 0..expected_claim_queue_len { let core_idx = CoreIndex::from(core_idx); + Self::fill_claim_queue(core_idx, n_lookahead); + } + } - let n_lookahead_used = cq.get(&core_idx).map_or(0, |v| v.len() as u32); - - // add previously timedout paras back into the queue - if let Some(mut entry) = timedout_paras.remove(&core_idx) { - if entry.availability_timeouts < max_availability_timeouts { - // Increment the timeout counter. - entry.availability_timeouts += 1; - if n_lookahead_used < n_lookahead { - entry.ttl = now + ttl; - } else { - // Over max capacity, we need to bump ttl (we exceeded the claim queue - // size, so otherwise the entry might get dropped before reaching the top): - entry.ttl = now + ttl + One::one(); - } - Self::add_to_claim_queue(core_idx, entry); - // The claim has been added back into the claim queue. - // Do not pop another assignment for the core. - continue - } else { - // Consider timed out assignments for on demand parachains as concluded for - // the assignment provider - let ret = concluded_paras.insert(core_idx, entry.assignment); - debug_assert!(ret.is_none()); + /// Push some assignments back to the provider. + fn push_back_to_assignment_provider( + assignments: impl core::iter::DoubleEndedIterator, + ) { + // Push back in reverse order so that when we pop from the provider again, + // the entries in the claim queue are in the same order as they are right + // now. + for assignment in assignments.rev() { + T::AssignmentProvider::push_back_assignment(assignment); + } + } + + fn fill_claim_queue(core_idx: CoreIndex, n_lookahead: u32) { + ClaimQueue::::mutate(|la| { + let cq = la.entry(core_idx).or_default(); + + let mut n_lookahead_used = cq.len() as u32; + + // If the claim queue used to be empty, we need to double the first assignment. + // Otherwise, the para will only be able to get the collation in right at the next block + // (synchronous backing). + // Only do this if the configured lookahead is greater than 1. Otherwise, it doesn't + // make sense. + if n_lookahead_used == 0 && n_lookahead > 1 { + if let Some(assignment) = T::AssignmentProvider::pop_assignment_for_core(core_idx) { + T::AssignmentProvider::assignment_duplicated(&assignment); + cq.push_back(assignment.clone()); + cq.push_back(assignment); + n_lookahead_used += 2; } } - if let Some(concluded_para) = concluded_paras.remove(&core_idx) { - T::AssignmentProvider::report_processed(concluded_para); - } for _ in n_lookahead_used..n_lookahead { if let Some(assignment) = T::AssignmentProvider::pop_assignment_for_core(core_idx) { - Self::add_to_claim_queue(core_idx, ParasEntry::new(assignment, now + ttl)); + cq.push_back(assignment); + } else { + break } } - } - - debug_assert!(timedout_paras.is_empty()); - debug_assert!(concluded_paras.is_empty()); - } - fn add_to_claim_queue(core_idx: CoreIndex, pe: ParasEntryType) { - ClaimQueue::::mutate(|la| { - la.entry(core_idx).or_default().push_back(pe); + // If we didn't end up pushing anything, remove the entry. We don't want to waste the + // space if we've no assignments. + if cq.is_empty() { + la.remove(&core_idx); + } }); } - /// Returns `ParasEntry` with `para_id` at `core_idx` if found. - fn remove_from_claim_queue( - core_idx: CoreIndex, - para_id: ParaId, - ) -> Result<(PositionInClaimQueue, ParasEntryType), &'static str> { - ClaimQueue::::mutate(|cq| { - let core_claims = cq.get_mut(&core_idx).ok_or("core_idx not found in lookahead")?; - - let pos = core_claims - .iter() - .position(|pe| pe.para_id() == para_id) - .ok_or("para id not found at core_idx lookahead")?; - - let pe = core_claims.remove(pos).ok_or("remove returned None")?; - - Ok((pos as u32, pe)) - }) - } - - /// Paras scheduled next in the claim queue. - pub(crate) fn scheduled_paras() -> impl Iterator { - let claim_queue = ClaimQueue::::get(); - claim_queue - .into_iter() - .filter_map(|(core_idx, v)| v.front().map(|e| (core_idx, e.assignment.para_id()))) - } - - /// Paras that may get backed on cores. - /// - /// 1. The para must be scheduled on core. - /// 2. Core needs to be free, otherwise backing is not possible. - pub(crate) fn eligible_paras() -> impl Iterator { - let availability_cores = AvailabilityCores::::get(); - - Self::claim_queue_iterator().zip(availability_cores.into_iter()).filter_map( - |((core_idx, queue), core)| { - if core != CoreOccupied::Free { - return None - } - let next_scheduled = queue.front()?; - Some((core_idx, next_scheduled.assignment.para_id())) - }, - ) + fn pop_front_of_claim_queue(core_idx: &CoreIndex) -> Option { + ClaimQueue::::mutate(|cq| cq.get_mut(core_idx)?.pop_front()) } #[cfg(any(feature = "try-runtime", test))] @@ -726,7 +453,7 @@ impl Pallet { } #[cfg(test)] - pub(crate) fn set_claim_queue(claim_queue: BTreeMap>>) { + pub(crate) fn set_claim_queue(claim_queue: BTreeMap>) { ClaimQueue::::set(claim_queue); } } diff --git a/polkadot/runtime/parachains/src/scheduler/common.rs b/polkadot/runtime/parachains/src/scheduler/common.rs index 114cd4b940bc..bf8a2bee74e3 100644 --- a/polkadot/runtime/parachains/src/scheduler/common.rs +++ b/polkadot/runtime/parachains/src/scheduler/common.rs @@ -77,11 +77,6 @@ pub trait AssignmentProvider { #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(core_idx: CoreIndex, para_id: ParaId) -> Assignment; - /// How many cores are allocated to this provider. - /// - /// As the name suggests the core count has to be session buffered: - /// - /// - Core count has to be predetermined for the next session in the current session. - /// - Core count must not change during a session. - fn session_core_count() -> u32; + /// Report that an assignment was duplicated by the scheduler. + fn assignment_duplicated(assignment: &Assignment); } diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index 125f105ef706..e741711cad6d 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -268,7 +268,7 @@ pub type MigrateV0ToV1 = VersionedMigration< ::DbWeight, >; -mod v2 { +pub(crate) mod v2 { use super::*; use crate::scheduler; @@ -406,3 +406,89 @@ pub type MigrateV1ToV2 = VersionedMigration< Pallet, ::DbWeight, >; + +/// Migration for TTL and availability timeout retries removal. +/// AvailabilityCores storage is removed and ClaimQueue now holds `Assignment`s instead of +/// `ParasEntryType` +mod v3 { + use super::*; + use crate::scheduler; + + #[storage_alias] + pub(crate) type ClaimQueue = + StorageValue, BTreeMap>, ValueQuery>; + /// Migration to V3 + pub struct UncheckedMigrateToV3(core::marker::PhantomData); + + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV3 { + fn on_runtime_upgrade() -> Weight { + let mut weight: Weight = Weight::zero(); + + // Migrate ClaimQueuee to new format. + + let old = v2::ClaimQueue::::take(); + let new = old + .into_iter() + .map(|(k, v)| { + ( + k, + v.into_iter() + .map(|paras_entry| paras_entry.assignment) + .collect::>(), + ) + }) + .collect::>>(); + + v3::ClaimQueue::::put(new); + + // Clear AvailabilityCores storage + v2::AvailabilityCores::::kill(); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + log::info!(target: scheduler::LOG_TARGET, "Migrating para scheduler storage to v3"); + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + log::trace!( + target: crate::scheduler::LOG_TARGET, + "ClaimQueue before migration: {}", + v2::ClaimQueue::::get().len() + ); + + let bytes = u32::to_be_bytes(v2::ClaimQueue::::get().len() as u32); + + Ok(bytes.to_vec()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::DispatchError> { + log::trace!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); + + let old_len = u32::from_be_bytes(state.try_into().unwrap()); + ensure!( + v3::ClaimQueue::::get().len() as u32 == old_len, + "Old ClaimQueue completely moved to new ClaimQueue after migration" + ); + + ensure!( + !v2::AvailabilityCores::::exists(), + "AvailabilityCores storage should have been completely killed" + ); + + Ok(()) + } + } +} + +/// Migrate `V2` to `V3` of the storage format. +pub type MigrateV2ToV3 = VersionedMigration< + 2, + 3, + v3::UncheckedMigrateToV3, + Pallet, + ::DbWeight, +>; diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index 5f80114b5963..431562c6e6fb 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -16,7 +16,7 @@ use super::*; -use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; +use alloc::collections::btree_map::BTreeMap; use frame_support::assert_ok; use polkadot_primitives::{ BlockNumber, SchedulerParams, SessionIndex, ValidationCode, ValidatorId, @@ -27,14 +27,14 @@ use crate::{ configuration::HostConfiguration, initializer::SessionChangeNotification, mock::{ - new_test_ext, MockAssigner, MockGenesisConfig, Paras, ParasShared, RuntimeOrigin, - Scheduler, System, Test, + new_test_ext, Configuration, MockAssigner, MockGenesisConfig, Paras, ParasShared, + RuntimeOrigin, Scheduler, System, Test, }, paras::{ParaGenesisArgs, ParaKind}, scheduler::{self, common::Assignment, ClaimQueue}, }; -fn schedule_blank_para(id: ParaId) { +fn register_para(id: ParaId) { let validation_code: ValidationCode = vec![1, 2, 3].into(); assert_ok!(Paras::schedule_para_initialize( id, @@ -58,17 +58,18 @@ fn run_to_block( Scheduler::initializer_finalize(); Paras::initializer_finalize(b); - if let Some(notification) = new_session(b + 1) { - let mut notification_with_session_index = notification; + if let Some(mut notification) = new_session(b + 1) { // We will make every session change trigger an action queue. Normally this may require // 2 or more session changes. - if notification_with_session_index.session_index == SessionIndex::default() { - notification_with_session_index.session_index = ParasShared::scheduled_session(); + if notification.session_index == SessionIndex::default() { + notification.session_index = ParasShared::scheduled_session(); } - Scheduler::pre_new_session(); - Paras::initializer_on_new_session(¬ification_with_session_index); - Scheduler::initializer_on_new_session(¬ification_with_session_index); + Configuration::force_set_active_config(notification.new_config.clone()); + + Paras::initializer_on_new_session(¬ification); + + Scheduler::initializer_on_new_session(¬ification); } System::on_finalize(b); @@ -79,28 +80,8 @@ fn run_to_block( Paras::initializer_initialize(b + 1); Scheduler::initializer_initialize(b + 1); - // In the real runtime this is expected to be called by the `InclusionInherent` pallet. - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); - } -} - -fn run_to_end_of_block( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, -) { - run_to_block(to, &new_session); - - Scheduler::initializer_finalize(); - Paras::initializer_finalize(to); - - if let Some(notification) = new_session(to + 1) { - Scheduler::pre_new_session(); - - Paras::initializer_on_new_session(¬ification); - Scheduler::initializer_on_new_session(¬ification); + Scheduler::advance_claim_queue(&Default::default()); } - - System::on_finalize(to); } fn default_config() -> HostConfiguration { @@ -110,6 +91,7 @@ fn default_config() -> HostConfiguration { // `minimum_validation_upgrade_delay` is greater than `chain_availability_period` and // `thread_availability_period`. minimum_validation_upgrade_delay: 6, + #[allow(deprecated)] scheduler_params: SchedulerParams { group_rotation_frequency: 10, paras_availability_period: 3, @@ -129,172 +111,27 @@ fn genesis_config(config: &HostConfiguration) -> MockGenesisConfig } } -fn claimqueue_contains_para_ids(pids: Vec) -> bool { - let set: BTreeSet = ClaimQueue::::get() +/// Internal access to assignments at the top of the claim queue. +fn next_assignments() -> impl Iterator { + let claim_queue = ClaimQueue::::get(); + claim_queue .into_iter() - .flat_map(|(_, paras_entries)| paras_entries.into_iter().map(|pe| pe.assignment.para_id())) - .collect(); - - pids.into_iter().all(|pid| set.contains(&pid)) -} - -fn availability_cores_contains_para_ids(pids: Vec) -> bool { - let set: BTreeSet = AvailabilityCores::::get() - .into_iter() - .filter_map(|core| match core { - CoreOccupied::Free => None, - CoreOccupied::Paras(entry) => Some(entry.para_id()), - }) - .collect(); - - pids.into_iter().all(|pid| set.contains(&pid)) -} - -/// Internal access to entries at the top of the claim queue. -fn scheduled_entries() -> impl Iterator>)> { - let claimqueue = ClaimQueue::::get(); - claimqueue - .into_iter() - .filter_map(|(core_idx, v)| v.front().map(|e| (core_idx, e.clone()))) -} - -#[test] -fn claim_queue_iterator_handles_holes_correctly() { - let mut queue = BTreeMap::new(); - queue.insert(CoreIndex(1), ["abc"].into_iter().collect()); - queue.insert(CoreIndex(4), ["cde"].into_iter().collect()); - let queue = queue.into_iter().peekable(); - let mut i = ClaimQueueIterator { next_idx: 0, queue }; - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(0)); - assert!(e.is_empty()); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(1)); - assert!(e.len() == 1); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(2)); - assert!(e.is_empty()); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(3)); - assert!(e.is_empty()); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(4)); - assert!(e.len() == 1); - - assert!(i.next().is_none()); + .filter_map(|(core_idx, v)| v.front().map(|a| (core_idx, a.clone()))) } #[test] -fn claimqueue_ttl_drop_fn_works() { +fn session_change_shuffles_validators() { let mut config = default_config(); - config.scheduler_params.lookahead = 3; + // Need five cores for this test + config.scheduler_params.num_cores = 5; let genesis_config = genesis_config(&config); - let para_id = ParaId::from(100); - let core_idx = CoreIndex::from(0); - let mut now = 10; - new_test_ext(genesis_config).execute_with(|| { - assert!(config.scheduler_params.ttl == 5); - // Register and run to a blockheight where the para is in a valid state. - schedule_blank_para(para_id); - run_to_block(now, |n| if n == now { Some(Default::default()) } else { None }); - - // Add a claim on core 0 with a ttl in the past. - let paras_entry = ParasEntry::new(Assignment::Bulk(para_id), now - 5 as u32); - Scheduler::add_to_claim_queue(core_idx, paras_entry.clone()); - - // Claim is in queue prior to call. - assert!(claimqueue_contains_para_ids::(vec![para_id])); - - // Claim is dropped post call. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(!claimqueue_contains_para_ids::(vec![para_id])); - - // Add a claim on core 0 with a ttl in the future (15). - let paras_entry = ParasEntry::new(Assignment::Bulk(para_id), now + 5); - Scheduler::add_to_claim_queue(core_idx, paras_entry.clone()); - - // Claim is in queue post call. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(claimqueue_contains_para_ids::(vec![para_id])); - - now = now + 6; - run_to_block(now, |_| None); - - // Claim is dropped - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(!claimqueue_contains_para_ids::(vec![para_id])); - - // Add a claim on core 0 with a ttl == now (16) - let paras_entry = ParasEntry::new(Assignment::Bulk(para_id), now); - Scheduler::add_to_claim_queue(core_idx, paras_entry.clone()); - - // Claim is in queue post call. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(claimqueue_contains_para_ids::(vec![para_id])); - - now = now + 1; - run_to_block(now, |_| None); - - // Drop expired claim. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(!claimqueue_contains_para_ids::(vec![para_id])); - - // Add a claim on core 0 with a ttl == now (17) - let paras_entry_non_expired = ParasEntry::new(Assignment::Bulk(para_id), now); - let paras_entry_expired = ParasEntry::new(Assignment::Bulk(para_id), now - 2); - // ttls = [17, 15, 17] - Scheduler::add_to_claim_queue(core_idx, paras_entry_non_expired.clone()); - Scheduler::add_to_claim_queue(core_idx, paras_entry_expired.clone()); - Scheduler::add_to_claim_queue(core_idx, paras_entry_non_expired.clone()); - let cq = scheduler::ClaimQueue::::get(); - assert_eq!(cq.get(&core_idx).unwrap().len(), 3); - - // Add a claim to the test assignment provider. - let assignment = Assignment::Bulk(para_id); - - MockAssigner::add_test_assignment(assignment.clone()); - - // Drop expired claim. - Scheduler::drop_expired_claims_from_claim_queue(); - - let cq = scheduler::ClaimQueue::::get(); - let cqc = cq.get(&core_idx).unwrap(); - // Same number of claims, because a new claim is popped from `MockAssigner` instead of the - // expired one - assert_eq!(cqc.len(), 3); - - // The first 2 claims in the queue should have a ttl of 17, - // being the ones set up prior in this test as claims 1 and 3. - // The third claim is popped from the assignment provider and - // has a new ttl set by the scheduler of now + - // assignment_provider_ttl. ttls = [17, 17, 22] - assert!(cqc.iter().enumerate().all(|(index, entry)| { - match index { - 0 | 1 => entry.clone().ttl == 17, - 2 => entry.clone().ttl == 22, - _ => false, - } - })) - }); -} - -#[test] -fn session_change_shuffles_validators() { - let genesis_config = genesis_config(&default_config()); + assert!(ValidatorGroups::::get().is_empty()); - new_test_ext(genesis_config).execute_with(|| { - // Need five cores for this test - MockAssigner::set_core_count(5); run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), @@ -328,6 +165,8 @@ fn session_change_shuffles_validators() { fn session_change_takes_only_max_per_core() { let config = { let mut config = default_config(); + // Simulate 2 cores between all usage types + config.scheduler_params.num_cores = 2; config.scheduler_params.max_validators_per_core = Some(1); config }; @@ -335,9 +174,6 @@ fn session_change_takes_only_max_per_core() { let genesis_config = genesis_config(&config); new_test_ext(genesis_config).execute_with(|| { - // Simulate 2 cores between all usage types - MockAssigner::set_core_count(2); - run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { new_config: config.clone(), @@ -367,8 +203,12 @@ fn session_change_takes_only_max_per_core() { } #[test] -fn fill_claimqueue_fills() { - let config = default_config(); +// Test that `advance_claim_queue` doubles the first assignment only for a core that didn't use to +// have any assignments. +fn advance_claim_queue_doubles_assignment_only_if_empty() { + let mut config = default_config(); + config.scheduler_params.lookahead = 3; + config.scheduler_params.num_cores = 2; let genesis_config = genesis_config(&config); let para_a = ParaId::from(3_u32); @@ -380,18 +220,15 @@ fn fill_claimqueue_fills() { let assignment_c = Assignment::Bulk(para_c); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(2); - let coretime_ttl = config.scheduler_params.ttl; - // Add 3 paras - schedule_blank_para(para_a); - schedule_blank_para(para_b); - schedule_blank_para(para_c); + register_para(para_a); + register_para(para_b); + register_para(para_c); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), @@ -406,224 +243,108 @@ fn fill_claimqueue_fills() { MockAssigner::add_test_assignment(assignment_b.clone()); MockAssigner::add_test_assignment(assignment_c.clone()); + // This will call advance_claim_queue run_to_block(2, |_| None); { - assert_eq!(Scheduler::claim_queue_len(), 3); - let scheduled: BTreeMap<_, _> = scheduled_entries().collect(); + assert_eq!(Scheduler::claim_queue_len(), 5); + let mut claim_queue = scheduler::ClaimQueue::::get(); - // Was added a block later, note the TTL. + // Because the claim queue used to be empty, the first assignment is doubled for every + // core so that the first para gets a fair shot at backing something. assert_eq!( - scheduled.get(&CoreIndex(0)).unwrap(), - &ParasEntry { - assignment: assignment_a.clone(), - availability_timeouts: 0, - ttl: 2 + coretime_ttl - }, - ); - // Sits on the same core as `para_a` - assert_eq!( - scheduler::ClaimQueue::::get().get(&CoreIndex(0)).unwrap()[1], - ParasEntry { - assignment: assignment_b.clone(), - availability_timeouts: 0, - ttl: 2 + coretime_ttl - } + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a, assignment_b] + .into_iter() + .collect::>() ); assert_eq!( - scheduled.get(&CoreIndex(1)).unwrap(), - &ParasEntry { - assignment: assignment_c.clone(), - availability_timeouts: 0, - ttl: 2 + coretime_ttl - }, + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_c.clone(), assignment_c].into_iter().collect::>() ); } }); } #[test] -fn schedule_schedules_including_just_freed() { +// Test that `advance_claim_queue` doesn't populate for cores which have no assignments. +fn advance_claim_queue_no_entry_if_empty() { let mut config = default_config(); - // NOTE: This test expects on demand cores to each get slotted on to a different core - // and not fill up the claimqueue of each core first. - config.scheduler_params.lookahead = 1; + config.scheduler_params.lookahead = 3; + config.scheduler_params.num_cores = 2; let genesis_config = genesis_config(&config); let para_a = ParaId::from(3_u32); - let para_b = ParaId::from(4_u32); - let para_c = ParaId::from(5_u32); - let para_d = ParaId::from(6_u32); - let para_e = ParaId::from(7_u32); - let assignment_a = Assignment::Bulk(para_a); - let assignment_b = Assignment::Bulk(para_b); - let assignment_c = Assignment::Bulk(para_c); - let assignment_d = Assignment::Bulk(para_d); - let assignment_e = Assignment::Bulk(para_e); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(3); - - // add 5 paras - schedule_blank_para(para_a); - schedule_blank_para(para_b); - schedule_blank_para(para_c); - schedule_blank_para(para_d); - schedule_blank_para(para_e); + // Add 1 para + register_para(para_a); - // start a new session to activate, 3 validators for 3 cores. + // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), ], ..Default::default() }), _ => None, }); - // add a couple of para claims now that paras are live MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_c.clone()); - let mut now = 2; - run_to_block(now, |_| None); - - assert_eq!(Scheduler::scheduled_paras().collect::>().len(), 2); - - // cores 0, 1 should be occupied. mark them as such. - let mut occupied_map: BTreeMap = BTreeMap::new(); - occupied_map.insert(CoreIndex(0), para_a); - occupied_map.insert(CoreIndex(1), para_c); - Scheduler::occupied(occupied_map); - - { - let cores = AvailabilityCores::::get(); - - // cores 0, 1 are `CoreOccupied::Paras(ParasEntry...)` - assert!(cores[0] != CoreOccupied::Free); - assert!(cores[1] != CoreOccupied::Free); - - // core 2 is free - assert!(cores[2] == CoreOccupied::Free); - - assert!(Scheduler::scheduled_paras().collect::>().is_empty()); - - // All `core_queue`s should be empty - scheduler::ClaimQueue::::get() - .iter() - .for_each(|(_core_idx, core_queue)| assert_eq!(core_queue.len(), 0)) - } - - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_c.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); - MockAssigner::add_test_assignment(assignment_d.clone()); - MockAssigner::add_test_assignment(assignment_e.clone()); - now = 3; - run_to_block(now, |_| None); - - { - let scheduled: BTreeMap<_, _> = scheduled_entries().collect(); - - assert_eq!(scheduled.len(), 3); - assert_eq!( - scheduled.get(&CoreIndex(2)).unwrap(), - &ParasEntry { - assignment: Assignment::Bulk(para_b), - availability_timeouts: 0, - ttl: 8 - }, - ); - } - - // now note that cores 0 and 1 were freed. - let just_updated: BTreeMap = vec![ - (CoreIndex(0), FreedReason::Concluded), - (CoreIndex(1), FreedReason::TimedOut), // should go back on queue. - ] - .into_iter() - .collect(); - Scheduler::free_cores_and_fill_claim_queue(just_updated, now); + // This will call advance_claim_queue + run_to_block(3, |_| None); { - let scheduled: BTreeMap<_, _> = scheduled_entries().collect(); + let mut claim_queue = scheduler::ClaimQueue::::get(); - // 1 thing scheduled before, + 2 cores freed. - assert_eq!(scheduled.len(), 3); - assert_eq!( - scheduled.get(&CoreIndex(0)).unwrap(), - &ParasEntry { - // Next entry in queue is `a` again: - assignment: Assignment::Bulk(para_a), - availability_timeouts: 0, - ttl: 8 - }, - ); - // Although C was descheduled, the core `2` was occupied so C goes back to the queue. - assert_eq!( - scheduler::ClaimQueue::::get()[&CoreIndex(1)][1], - ParasEntry { - assignment: Assignment::Bulk(para_c), - // End of the queue should be the pushed back entry: - availability_timeouts: 1, - // ttl 1 higher: - ttl: 9 - }, - ); - assert_eq!( - scheduled.get(&CoreIndex(1)).unwrap(), - &ParasEntry { - assignment: Assignment::Bulk(para_c), - availability_timeouts: 0, - ttl: 8 - }, - ); assert_eq!( - scheduled.get(&CoreIndex(2)).unwrap(), - &ParasEntry { - assignment: Assignment::Bulk(para_b), - availability_timeouts: 0, - ttl: 8 - }, + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a].into_iter().collect::>() ); - assert!(claimqueue_contains_para_ids::(vec![para_c])); - assert!(!availability_cores_contains_para_ids::(vec![para_a, para_c])); + // Even though core 1 exists, there's no assignment for it so it's not present in the + // claim queue. + assert!(claim_queue.remove(&CoreIndex(1)).is_none()); } }); } #[test] -fn schedule_clears_availability_cores() { +// Test that `advance_claim_queue` only advances for cores that are not part of the `except_for` +// set. +fn advance_claim_queue_except_for() { let mut config = default_config(); + // NOTE: This test expects on demand cores to each get slotted on to a different core + // and not fill up the claimqueue of each core first. config.scheduler_params.lookahead = 1; + config.scheduler_params.num_cores = 3; + let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); let para_b = ParaId::from(2_u32); let para_c = ParaId::from(3_u32); + let para_d = ParaId::from(4_u32); + let para_e = ParaId::from(5_u32); let assignment_a = Assignment::Bulk(para_a); let assignment_b = Assignment::Bulk(para_b); let assignment_c = Assignment::Bulk(para_c); + let assignment_d = Assignment::Bulk(para_d); + let assignment_e = Assignment::Bulk(para_e); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(3); - - // register 3 paras - schedule_blank_para(para_a); - schedule_blank_para(para_b); - schedule_blank_para(para_c); - - // Adding assignments then running block to populate claim queue - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); - MockAssigner::add_test_assignment(assignment_c.clone()); + // add 5 paras + register_para(para_a); + register_para(para_b); + register_para(para_c); + register_para(para_d); + register_para(para_e); // start a new session to activate, 3 validators for 3 cores. run_to_block(1, |number| match number { @@ -639,91 +360,69 @@ fn schedule_clears_availability_cores() { _ => None, }); - run_to_block(2, |_| None); - - assert_eq!(scheduler::ClaimQueue::::get().len(), 3); - - // cores 0, 1, and 2 should be occupied. mark them as such. - Scheduler::occupied( - vec![(CoreIndex(0), para_a), (CoreIndex(1), para_b), (CoreIndex(2), para_c)] - .into_iter() - .collect(), - ); + // add a couple of para claims now that paras are live + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_c.clone()); - { - let cores = AvailabilityCores::::get(); + run_to_block(2, |_| None); - assert_eq!(cores[0].is_free(), false); - assert_eq!(cores[1].is_free(), false); - assert_eq!(cores[2].is_free(), false); + Scheduler::advance_claim_queue(&Default::default()); - // All `core_queue`s should be empty - scheduler::ClaimQueue::::get() - .iter() - .for_each(|(_core_idx, core_queue)| assert!(core_queue.len() == 0)) - } + // Queues of all cores should be empty + assert_eq!(Scheduler::claim_queue_len(), 0); - // Add more assignments MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); MockAssigner::add_test_assignment(assignment_c.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + MockAssigner::add_test_assignment(assignment_d.clone()); + MockAssigner::add_test_assignment(assignment_e.clone()); run_to_block(3, |_| None); - // now note that cores 0 and 2 were freed. - Scheduler::free_cores_and_fill_claim_queue( - vec![(CoreIndex(0), FreedReason::Concluded), (CoreIndex(2), FreedReason::Concluded)] - .into_iter() - .collect::>(), - 3, - ); + { + let scheduled: BTreeMap<_, _> = next_assignments().collect(); + + assert_eq!(scheduled.len(), 3); + assert_eq!(scheduled.get(&CoreIndex(0)).unwrap(), &Assignment::Bulk(para_a)); + assert_eq!(scheduled.get(&CoreIndex(1)).unwrap(), &Assignment::Bulk(para_c)); + assert_eq!(scheduled.get(&CoreIndex(2)).unwrap(), &Assignment::Bulk(para_b)); + } + + // now note that cores 0 and 1 were freed. + Scheduler::advance_claim_queue(&std::iter::once(CoreIndex(2)).collect()); { - let claimqueue = ClaimQueue::::get(); - let claimqueue_0 = claimqueue.get(&CoreIndex(0)).unwrap().clone(); - let claimqueue_2 = claimqueue.get(&CoreIndex(2)).unwrap().clone(); - let entry_ttl = 8; - assert_eq!(claimqueue_0.len(), 1); - assert_eq!(claimqueue_2.len(), 1); - let queue_0_expectation: VecDeque> = - vec![ParasEntry::new(assignment_a, entry_ttl as u32)].into_iter().collect(); - let queue_2_expectation: VecDeque> = - vec![ParasEntry::new(assignment_c, entry_ttl as u32)].into_iter().collect(); - assert_eq!(claimqueue_0, queue_0_expectation); - assert_eq!(claimqueue_2, queue_2_expectation); - - // The freed cores should be `Free` in `AvailabilityCores`. - let cores = AvailabilityCores::::get(); - assert!(cores[0].is_free()); - assert!(cores[2].is_free()); + let scheduled: BTreeMap<_, _> = next_assignments().collect(); + + // 1 thing scheduled before, + 2 cores freed. + assert_eq!(scheduled.len(), 3); + assert_eq!(scheduled.get(&CoreIndex(0)).unwrap(), &Assignment::Bulk(para_d)); + assert_eq!(scheduled.get(&CoreIndex(1)).unwrap(), &Assignment::Bulk(para_e)); + assert_eq!(scheduled.get(&CoreIndex(2)).unwrap(), &Assignment::Bulk(para_b)); } }); } #[test] fn schedule_rotates_groups() { + let on_demand_cores = 2; let config = { let mut config = default_config(); config.scheduler_params.lookahead = 1; + config.scheduler_params.num_cores = on_demand_cores; config }; let rotation_frequency = config.scheduler_params.group_rotation_frequency; - let on_demand_cores = 2; let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); let para_b = ParaId::from(2_u32); - let assignment_a = Assignment::Bulk(para_a); - let assignment_b = Assignment::Bulk(para_b); - new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(on_demand_cores); - - schedule_blank_para(para_a); - schedule_blank_para(para_b); + register_para(para_a); + register_para(para_b); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { @@ -741,15 +440,10 @@ fn schedule_rotates_groups() { let session_start_block = scheduler::SessionStartBlock::::get(); assert_eq!(session_start_block, 1); - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); - let mut now = 2; run_to_block(now, |_| None); let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor| { - let scheduled: BTreeMap<_, _> = Scheduler::scheduled_paras().collect(); - assert_eq!(scheduled.len(), 2); assert_eq!( Scheduler::group_assigned_to_core(CoreIndex(0), *now).unwrap(), GroupIndex((0u32 + rotations) % on_demand_cores) @@ -764,7 +458,7 @@ fn schedule_rotates_groups() { // one block before first rotation. now = rotation_frequency; - run_to_block(rotation_frequency, |_| None); + run_to_block(now, |_| None); assert_groups_rotated(0, &now); @@ -785,134 +479,6 @@ fn schedule_rotates_groups() { }); } -#[test] -fn on_demand_claims_are_pruned_after_timing_out() { - let max_timeouts = 20; - let mut config = default_config(); - config.scheduler_params.lookahead = 1; - // Need more timeouts for this test - config.scheduler_params.max_availability_timeouts = max_timeouts; - config.scheduler_params.ttl = BlockNumber::from(5u32); - let genesis_config = genesis_config(&config); - - let para_a = ParaId::from(1_u32); - - let assignment_a = Assignment::Bulk(para_a); - - new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(2); - schedule_blank_para(para_a); - - // #1 - let mut now = 1; - run_to_block(now, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - MockAssigner::add_test_assignment(assignment_a.clone()); - - // #2 - now += 1; - run_to_block(now, |_| None); - assert_eq!(scheduler::ClaimQueue::::get().len(), 1); - // ParaId a is in the claimqueue. - assert!(claimqueue_contains_para_ids::(vec![para_a])); - - Scheduler::occupied(vec![(CoreIndex(0), para_a)].into_iter().collect()); - // ParaId a is no longer in the claimqueue. - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - // It is in availability cores. - assert!(availability_cores_contains_para_ids::(vec![para_a])); - - // #3 - now += 1; - // Run to block #n over the max_retries value. - // In this case, both validator groups with time out on availability and - // the assignment will be dropped. - for n in now..=(now + max_timeouts + 1) { - // #n - run_to_block(n, |_| None); - // Time out on core 0. - let just_updated: BTreeMap = vec![ - (CoreIndex(0), FreedReason::TimedOut), // should go back on queue. - ] - .into_iter() - .collect(); - Scheduler::free_cores_and_fill_claim_queue(just_updated, now); - - // ParaId a exists in the claim queue until max_retries is reached. - if n < max_timeouts + now { - assert!(claimqueue_contains_para_ids::(vec![para_a])); - } else { - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - } - - let core_assignments = Scheduler::scheduled_paras().collect(); - Scheduler::occupied(core_assignments); - } - - // ParaId a does not exist in the claimqueue/availability_cores after - // threshold has been reached. - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - assert!(!availability_cores_contains_para_ids::(vec![para_a])); - - // #25 - now += max_timeouts + 2; - - // Add assignment back to the mix. - MockAssigner::add_test_assignment(assignment_a.clone()); - run_to_block(now, |_| None); - - assert!(claimqueue_contains_para_ids::(vec![para_a])); - - // #26 - now += 1; - // Run to block #n but this time have group 1 conclude the availability. - for n in now..=(now + max_timeouts + 1) { - // #n - run_to_block(n, |_| None); - // Time out core 0 if group 0 is assigned to it, if group 1 is assigned, conclude. - let mut just_updated: BTreeMap = BTreeMap::new(); - if let Some(group) = Scheduler::group_assigned_to_core(CoreIndex(0), n) { - match group { - GroupIndex(0) => { - just_updated.insert(CoreIndex(0), FreedReason::TimedOut); // should go back on queue. - }, - GroupIndex(1) => { - just_updated.insert(CoreIndex(0), FreedReason::Concluded); - }, - _ => panic!("Should only have 2 groups here"), - } - } - - Scheduler::free_cores_and_fill_claim_queue(just_updated, now); - - // ParaId a exists in the claim queue until groups are rotated. - if n < 31 { - assert!(claimqueue_contains_para_ids::(vec![para_a])); - } else { - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - } - - let core_assignments = Scheduler::scheduled_paras().collect(); - Scheduler::occupied(core_assignments); - } - - // ParaId a does not exist in the claimqueue/availability_cores after - // being concluded - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - assert!(!availability_cores_contains_para_ids::(vec![para_a])); - }); -} - #[test] fn availability_predicate_works() { let genesis_config = genesis_config(&default_config()); @@ -948,20 +514,21 @@ fn availability_predicate_works() { #[test] fn next_up_on_available_uses_next_scheduled_or_none() { - let genesis_config = genesis_config(&default_config()); + let mut config = default_config(); + config.scheduler_params.num_cores = 1; + let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); let para_b = ParaId::from(2_u32); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(1); - schedule_blank_para(para_a); - schedule_blank_para(para_b); + register_para(para_a); + register_para(para_b); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Eve.public()), @@ -971,69 +538,57 @@ fn next_up_on_available_uses_next_scheduled_or_none() { _ => None, }); - let entry_a = ParasEntry { - assignment: Assignment::Bulk(para_a), - availability_timeouts: 0 as u32, - ttl: 5 as u32, - }; - let entry_b = ParasEntry { - assignment: Assignment::Bulk(para_b), - availability_timeouts: 0 as u32, - ttl: 5 as u32, - }; - - Scheduler::add_to_claim_queue(CoreIndex(0), entry_a.clone()); + MockAssigner::add_test_assignment(Assignment::Bulk(para_a)); run_to_block(2, |_| None); { - assert_eq!(Scheduler::claim_queue_len(), 1); - assert_eq!(scheduler::AvailabilityCores::::get().len(), 1); - - let mut map = BTreeMap::new(); - map.insert(CoreIndex(0), para_a); - Scheduler::occupied(map); + // Two assignments for A on core 0, because the claim queue used to be empty. + assert_eq!(Scheduler::claim_queue_len(), 2); - let cores = scheduler::AvailabilityCores::::get(); - match &cores[0] { - CoreOccupied::Paras(entry) => assert_eq!(entry, &entry_a), - _ => panic!("There should only be one test assigner core"), - } - - assert!(Scheduler::next_up_on_available(CoreIndex(0)).is_none()); + assert!(Scheduler::next_up_on_available(CoreIndex(1)).is_none()); - Scheduler::add_to_claim_queue(CoreIndex(0), entry_b); + assert_eq!( + Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: para_a, collator: None } + ); + Scheduler::advance_claim_queue(&Default::default()); assert_eq!( Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: para_b, collator: None } + ScheduledCore { para_id: para_a, collator: None } ); + + Scheduler::advance_claim_queue(&Default::default()); + assert!(Scheduler::next_up_on_available(CoreIndex(0)).is_none()); } }); } #[test] -fn next_up_on_time_out_reuses_claim_if_nothing_queued() { - let genesis_config = genesis_config(&default_config()); +fn session_change_increasing_number_of_cores() { + let mut config = default_config(); + config.scheduler_params.num_cores = 2; + let genesis_config = genesis_config(&config); - let para_a = ParaId::from(1_u32); - let para_b = ParaId::from(2_u32); + let para_a = ParaId::from(3_u32); + let para_b = ParaId::from(4_u32); let assignment_a = Assignment::Bulk(para_a); let assignment_b = Assignment::Bulk(para_b); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(1); - schedule_blank_para(para_a); - schedule_blank_para(para_b); + // Add 2 paras + register_para(para_a); + register_para(para_b); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), ], ..Default::default() }), @@ -1041,193 +596,254 @@ fn next_up_on_time_out_reuses_claim_if_nothing_queued() { }); MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + // This will call advance_claim_queue run_to_block(2, |_| None); { - assert_eq!(scheduler::ClaimQueue::::get().len(), 1); - assert_eq!(scheduler::AvailabilityCores::::get().len(), 1); - - let mut map = BTreeMap::new(); - map.insert(CoreIndex(0), para_a); - Scheduler::occupied(map); - - let cores = scheduler::AvailabilityCores::::get(); - match cores.get(0).unwrap() { - CoreOccupied::Paras(entry) => { - assert_eq!(entry.assignment, assignment_a.clone()); - }, - _ => panic!("There should only be a single test assigner core"), - } - - // There's nothing more to pop for core 0 from the assignment provider. - assert!(MockAssigner::pop_assignment_for_core(CoreIndex(0)).is_none()); + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 4); assert_eq!( - Scheduler::next_up_on_time_out(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: para_a, collator: None } + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a.clone()] + .into_iter() + .collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_b.clone(), assignment_b.clone()] + .into_iter() + .collect::>() ); + } - MockAssigner::add_test_assignment(assignment_b.clone()); + // Increase number of cores to 4. + let old_config = config; + let mut new_config = old_config.clone(); + new_config.scheduler_params.num_cores = 4; - // Pop assignment_b into the claimqueue - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), 2); + // add another assignment for para b. + MockAssigner::add_test_assignment(assignment_b.clone()); + + run_to_block(3, |number| match number { + 3 => Some(SessionChangeNotification { + new_config: new_config.clone(), + prev_config: old_config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ], + ..Default::default() + }), + _ => None, + }); + + { + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 3); - //// Now that there is an earlier next-up, we use that. assert_eq!( - Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: para_b, collator: None } + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a].into_iter().collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_b.clone()].into_iter().collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(2)).unwrap(), + [assignment_b.clone()].into_iter().collect::>() ); } }); } #[test] -fn session_change_requires_reschedule_dropping_removed_paras() { +fn session_change_decreasing_number_of_cores() { let mut config = default_config(); - config.scheduler_params.lookahead = 1; + config.scheduler_params.num_cores = 3; let genesis_config = genesis_config(&config); - let para_a = ParaId::from(1_u32); - let para_b = ParaId::from(2_u32); + let para_a = ParaId::from(3_u32); + let para_b = ParaId::from(4_u32); let assignment_a = Assignment::Bulk(para_a); let assignment_b = Assignment::Bulk(para_b); new_test_ext(genesis_config).execute_with(|| { - // Setting explicit core count - MockAssigner::set_core_count(5); - let coretime_ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - - schedule_blank_para(para_a); - schedule_blank_para(para_b); - - // Add assignments - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); + // Add 2 paras + register_para(para_a); + register_para(para_b); + // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), ], - random_seed: [99; 32], ..Default::default() }), _ => None, }); - assert_eq!(scheduler::ClaimQueue::::get().len(), 2); + scheduler::Pallet::::set_claim_queue(BTreeMap::from([ + (CoreIndex::from(0), VecDeque::from([assignment_a.clone()])), + // Leave a hole for core 1. + (CoreIndex::from(2), VecDeque::from([assignment_b.clone(), assignment_b.clone()])), + ])); - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 5); + // Decrease number of cores to 1. + let old_config = config; + let mut new_config = old_config.clone(); + new_config.scheduler_params.num_cores = 1; - assert_ok!(Paras::schedule_para_cleanup(para_b)); + // Session change. + // Assignment A had its shot already so will be dropped for good. + // The two assignments of B will be pushed back to the assignment provider. + run_to_block(3, |number| match number { + 3 => Some(SessionChangeNotification { + new_config: new_config.clone(), + prev_config: old_config.clone(), + validators: vec![ValidatorId::from(Sr25519Keyring::Alice.public())], + ..Default::default() + }), + _ => None, + }); - // Add assignment - MockAssigner::add_test_assignment(assignment_a.clone()); + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 1); + + // There's only one assignment for B because run_to_block also calls advance_claim_queue at + // the end. + assert_eq!( + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_b.clone()].into_iter().collect::>() + ); + + 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); + }); +} + +#[test] +fn session_change_increasing_lookahead() { + let mut config = default_config(); + config.scheduler_params.num_cores = 2; + config.scheduler_params.lookahead = 2; + let genesis_config = genesis_config(&config); - run_to_end_of_block(2, |number| match number { - 2 => Some(SessionChangeNotification { - new_config: default_config(), + let para_a = ParaId::from(3_u32); + let para_b = ParaId::from(4_u32); + + let assignment_a = Assignment::Bulk(para_a); + let assignment_b = Assignment::Bulk(para_b); + + new_test_ext(genesis_config).execute_with(|| { + // Add 2 paras + register_para(para_a); + register_para(para_b); + + // start a new session to activate, 2 validators for 2 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), ], - random_seed: [99; 32], ..Default::default() }), _ => None, }); - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), 3); + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); - assert_eq!( - scheduler::ClaimQueue::::get(), - vec![( - CoreIndex(0), - vec![ParasEntry::new( - Assignment::Bulk(para_a), - // At end of block 2 - coretime_ttl + 2 - )] - .into_iter() - .collect() - )] - .into_iter() - .collect() - ); + // Lookahead is currently 2. - // Add para back - schedule_blank_para(para_b); + run_to_block(2, |_| None); - // Add assignments - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); + { + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 4); + + assert_eq!( + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a.clone()] + .into_iter() + .collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_a.clone(), assignment_a.clone()] + .into_iter() + .collect::>() + ); + } + + // Increase lookahead to 4. + let old_config = config; + let mut new_config = old_config.clone(); + new_config.scheduler_params.lookahead = 4; run_to_block(3, |number| match number { 3 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: new_config.clone(), + prev_config: old_config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), ], - random_seed: [99; 32], ..Default::default() }), _ => None, }); - assert_eq!(scheduler::ClaimQueue::::get().len(), 2); - - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 5); - - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), 4); + { + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 6); - assert_eq!( - scheduler::ClaimQueue::::get(), - vec![ - ( - CoreIndex(0), - vec![ParasEntry::new( - Assignment::Bulk(para_a), - // At block 3 - coretime_ttl + 3 - )] + assert_eq!( + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a.clone(), assignment_b.clone()] .into_iter() - .collect() - ), - ( - CoreIndex(1), - vec![ParasEntry::new( - Assignment::Bulk(para_b), - // At block 3 - coretime_ttl + 3 - )] + .collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_a.clone(), assignment_b.clone(), assignment_b.clone()] .into_iter() - .collect() - ), - ] - .into_iter() - .collect() - ); + .collect::>() + ); + } }); } diff --git a/polkadot/runtime/parachains/src/session_info.rs b/polkadot/runtime/parachains/src/session_info.rs index ea05c1aacaa9..0ec01755095b 100644 --- a/polkadot/runtime/parachains/src/session_info.rs +++ b/polkadot/runtime/parachains/src/session_info.rs @@ -135,8 +135,8 @@ impl Pallet { let assignment_keys = AssignmentKeysUnsafe::::get(); let active_set = shared::ActiveValidatorIndices::::get(); - let validator_groups = scheduler::ValidatorGroups::::get().into(); - let n_cores = scheduler::AvailabilityCores::::get().len() as u32; + let validator_groups = scheduler::ValidatorGroups::::get(); + let n_cores = validator_groups.len() as u32; let zeroth_delay_tranche_width = config.zeroth_delay_tranche_width; let relay_vrf_modulo_samples = config.relay_vrf_modulo_samples; let n_delay_tranches = config.n_delay_tranches; @@ -177,7 +177,7 @@ impl Pallet { validators, // these are from the notification and are thus already correct. discovery_keys: take_active_subset_and_inactive(&active_set, &discovery_keys), assignment_keys: take_active_subset(&active_set, &assignment_keys), - validator_groups, + validator_groups: validator_groups.into(), n_cores, zeroth_delay_tranche_width, relay_vrf_modulo_samples, diff --git a/polkadot/runtime/parachains/src/shared.rs b/polkadot/runtime/parachains/src/shared.rs index f582bf0d90b5..473c1aba7a06 100644 --- a/polkadot/runtime/parachains/src/shared.rs +++ b/polkadot/runtime/parachains/src/shared.rs @@ -80,6 +80,7 @@ impl /// Add a new relay-parent to the allowed relay parents, along with info about the header. /// Provide a maximum ancestry length for the buffer, which will cause old relay-parents to be /// pruned. + /// If the relay parent hash is already present, do nothing. pub(crate) fn update( &mut self, relay_parent: Hash, @@ -88,6 +89,11 @@ impl number: BlockNumber, max_ancestry_len: u32, ) { + if self.buffer.iter().any(|info| info.relay_parent == relay_parent) { + // Already present. + return + } + let claim_queue = transpose_claim_queue(claim_queue); // + 1 for the most recent block, which is always allowed. diff --git a/polkadot/runtime/parachains/src/shared/tests.rs b/polkadot/runtime/parachains/src/shared/tests.rs index 6da84e254f05..f7ea5148ce33 100644 --- a/polkadot/runtime/parachains/src/shared/tests.rs +++ b/polkadot/runtime/parachains/src/shared/tests.rs @@ -43,7 +43,13 @@ fn tracker_earliest_block_number() { let max_ancestry_len = 4; let now = 4; for i in 1..now { - tracker.update(Hash::zero(), Hash::zero(), Default::default(), i, max_ancestry_len); + tracker.update( + Hash::from([i as u8; 32]), + Hash::zero(), + Default::default(), + i, + max_ancestry_len, + ); assert_eq!(tracker.hypothetical_earliest_block_number(i + 1, max_ancestry_len), 0); } @@ -53,7 +59,7 @@ fn tracker_earliest_block_number() { } #[test] -fn tracker_claim_queue_remap() { +fn tracker_claim_queue_transpose() { let mut tracker = AllowedRelayParentsTracker::::default(); let mut claim_queue = BTreeMap::new(); @@ -120,6 +126,14 @@ fn tracker_acquire_info() { Some((s, b)) if s.state_root == state_root && b == 0 ); + // Try to push a duplicate. Should be ignored. + tracker.update(relay_parent, Hash::repeat_byte(13), Default::default(), 0, max_ancestry_len); + assert_eq!(tracker.buffer.len(), 1); + assert_matches!( + tracker.acquire_info(relay_parent, None), + Some((s, b)) if s.state_root == state_root && b == 0 + ); + let (relay_parent, state_root) = blocks[1]; tracker.update(relay_parent, state_root, Default::default(), 1u32, max_ancestry_len); let (relay_parent, state_root) = blocks[2]; diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 4aaaf94da586..3b11c977edf3 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -42,6 +42,7 @@ sp-storage = { workspace = true } sp-version = { workspace = true } sp-transaction-pool = { workspace = true } sp-block-builder = { workspace = true } +sp-keyring = { workspace = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } @@ -65,6 +66,7 @@ pallet-identity = { workspace = true } pallet-indices = { workspace = true } pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nis = { workspace = true } @@ -156,6 +158,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nis/std", @@ -238,6 +241,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nis/runtime-benchmarks", @@ -255,6 +259,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-tips/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", @@ -295,6 +300,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nis/try-runtime", diff --git a/polkadot/runtime/rococo/constants/src/weights/block_weights.rs b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs index e2aa4a6cab7f..f7dc2f19316d 100644 --- a/polkadot/runtime/rococo/constants/src/weights/block_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26 (Y/M/D) -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29 (Y/M/D) +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/rococo/constants/src/weights/` +//! WEIGHT-PATH: `./polkadot/runtime/rococo/constants/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: @@ -28,12 +28,11 @@ // benchmark // overhead // --chain=rococo-dev -// --execution=wasm // --wasm-execution=compiled -// --weight-path=runtime/rococo/constants/src/weights/ +// --weight-path=./polkadot/runtime/rococo/constants/src/weights/ // --warmup=10 // --repeat=100 -// --header=./file_header.txt +// --header=./polkadot/file_header.txt use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; @@ -43,17 +42,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 408_659, 450_716 - /// Average: 417_412 - /// Median: 411_177 - /// Std-Dev: 12242.31 + /// Min, Max: 440_142, 476_907 + /// Average: 450_240 + /// Median: 448_633 + /// Std-Dev: 7301.18 /// /// Percentiles nanoseconds: - /// 99th: 445_142 - /// 95th: 442_275 - /// 75th: 414_217 + /// 99th: 470_733 + /// 95th: 465_082 + /// 75th: 452_536 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(417_412), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(450_240), 0); } #[cfg(test)] diff --git a/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs b/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs index adce840ebbc1..000cee8a237c 100644 --- a/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26 (Y/M/D) -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29 (Y/M/D) +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/rococo/constants/src/weights/` +//! WEIGHT-PATH: `./polkadot/runtime/rococo/constants/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: @@ -28,12 +28,11 @@ // benchmark // overhead // --chain=rococo-dev -// --execution=wasm // --wasm-execution=compiled -// --weight-path=runtime/rococo/constants/src/weights/ +// --weight-path=./polkadot/runtime/rococo/constants/src/weights/ // --warmup=10 // --repeat=100 -// --header=./file_header.txt +// --header=./polkadot/file_header.txt use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; @@ -43,17 +42,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 97_574, 100_119 - /// Average: 98_236 - /// Median: 98_179 - /// Std-Dev: 394.9 + /// Min, Max: 92_961, 94_143 + /// Average: 93_369 + /// Median: 93_331 + /// Std-Dev: 217.39 /// /// Percentiles nanoseconds: - /// 99th: 99_893 - /// 95th: 98_850 - /// 75th: 98_318 + /// 99th: 93_848 + /// 95th: 93_691 + /// 75th: 93_514 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(98_236), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(93_369), 0); } #[cfg(test)] diff --git a/polkadot/runtime/rococo/src/genesis_config_presets.rs b/polkadot/runtime/rococo/src/genesis_config_presets.rs index c237dfd967f6..bdbf6f37d92c 100644 --- a/polkadot/runtime/rococo/src/genesis_config_presets.rs +++ b/polkadot/runtime/rococo/src/genesis_config_presets.rs @@ -23,30 +23,16 @@ use crate::{ #[cfg(not(feature = "std"))] use alloc::format; use alloc::{vec, vec::Vec}; -use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, SchedulerParams, ValidatorId}; +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; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{sr25519, Pair, Public}; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; use sp_genesis_builder::PresetId; -use sp_runtime::traits::IdentifyAccount; - -/// Helper function to generate a crypto pair from seed -fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed -fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} +use sp_keyring::Sr25519Keyring; /// Helper function to generate stash, controller and session key from seed fn get_authority_keys_from_seed( @@ -62,7 +48,16 @@ fn get_authority_keys_from_seed( BeefyId, ) { let keys = get_authority_keys_from_seed_no_beefy(seed); - (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5, keys.6, get_from_seed::(seed)) + ( + keys.0, + keys.1, + keys.2, + keys.3, + keys.4, + keys.5, + keys.6, + get_public_from_string_or_panic::(seed), + ) } /// Helper function to generate stash, controller and session key from seed @@ -70,31 +65,18 @@ fn get_authority_keys_from_seed_no_beefy( seed: &str, ) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } fn testnet_accounts() -> Vec { - Vec::from([ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ]) + Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect() } fn rococo_session_keys( @@ -182,7 +164,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::>(), }, @@ -204,9 +186,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 { @@ -217,14 +198,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 @@ -446,7 +421,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() @@ -459,26 +434,19 @@ 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 fn rococo_development_config_genesis() -> serde_json::Value { rococo_testnet_genesis( Vec::from([get_authority_keys_from_seed("Alice")]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -487,7 +455,7 @@ fn rococo_development_config_genesis() -> serde_json::Value { fn rococo_local_testnet_genesis() -> serde_json::Value { rococo_testnet_genesis( Vec::from([get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -502,18 +470,18 @@ fn versi_local_testnet_genesis() -> serde_json::Value { get_authority_keys_from_seed("Charlie"), get_authority_keys_from_seed("Dave"), ]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } /// 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..ab796edc54b1 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -21,7 +21,7 @@ use core::marker::PhantomData; use frame_support::pallet_prelude::DispatchResult; use frame_system::RawOrigin; use polkadot_primitives::Balance; -use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; +use polkadot_runtime_common::identity_migrator::OnReapIdentity; use rococo_runtime_constants::currency::*; use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm}; use xcm_executor::traits::TransactAsset; @@ -88,10 +88,7 @@ where AccountId: Into<[u8; 32]> + Clone + Encode, { fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult { - use crate::{ - impls::IdentityMigratorCalls::PokeDeposit, - weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights, - }; + use crate::impls::IdentityMigratorCalls::PokeDeposit; let total_to_send = Self::calculate_remote_deposit(fields, subs); @@ -144,7 +141,6 @@ where .into(); let poke = PeopleRuntimePallets::::IdentityMigrator(PokeDeposit(who.clone())); - let remote_weight_limit = MigratorWeights::::poke_deposit().saturating_mul(2); // Actual program to execute on People Chain. let program: Xcm<()> = Xcm(vec![ @@ -161,18 +157,14 @@ where .into(), }, // 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(), - }, + Transact { origin_kind: OriginKind::Superuser, call: poke.encode().into() }, ]); // 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(()) } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index ab6563525ff7..96a97faa4750 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -33,6 +33,7 @@ use frame_support::{ dynamic_params::{dynamic_pallet_params, dynamic_params}, traits::FromContains, }; +use pallet_balances::WeightInfo; use pallet_nis::WithMaximumOf; use polkadot_primitives::{ slashing, @@ -99,11 +100,10 @@ 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, - Extrinsic as ExtrinsicT, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, - Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, IdentityLookup, + Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, @@ -112,7 +112,10 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::{latest::prelude::*, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; +use xcm::{ + latest::prelude::*, VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, + VersionedXcm, +}; use xcm_builder::PayOverXcm; pub use frame_system::Call as SystemCall; @@ -165,8 +168,8 @@ 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, impl_version: 0, @@ -218,8 +221,10 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } parameter_types! { @@ -417,6 +422,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -537,6 +543,7 @@ impl pallet_treasury::Config for Runtime { AssetRate, >; type PayoutPeriod = PayoutSpendPeriod; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments; } @@ -605,18 +612,33 @@ impl pallet_grandpa::Config for Runtime { pallet_grandpa::EquivocationReportSystem; } -/// Submits a transaction with the node's public and signature type. Adheres to the signed extension -/// format of the chain. +impl frame_system::offchain::SigningTypes for Runtime { + type Public = ::Signer; + type Signature = Signature; +} + +impl frame_system::offchain::CreateTransactionBase for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type RuntimeCall = RuntimeCall; +} + +/// Submits a transaction with the node's public and signature type. Adheres to the signed +/// extension format of the chain. impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { use sp_runtime::traits::StaticLookup; // take the biggest period possible. let period = @@ -628,7 +650,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -641,31 +663,39 @@ where frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), frame_metadata_hash_extension::CheckMetadataHash::new(true), - ); - - let raw_payload = SignedPayload::new(call, extra) + ) + .into(); + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); + let (call, tx_ext, _) = raw_payload.deconstruct(); let address = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) + let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext); + Some(transaction) } } -impl frame_system::offchain::SigningTypes for Runtime { - type Public = ::Signer; - type Signature = Signature; +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: RuntimeCall, tx_ext: Self::Extension) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_transaction(call, tx_ext) + } } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateInherent for Runtime where - RuntimeCall: From, + RuntimeCall: From, { - type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + fn create_inherent(call: RuntimeCall) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_bare(call) + } } parameter_types! { @@ -684,6 +714,7 @@ parameter_types! { // Minimum 100 bytes/ROC deposited (1 CENT/byte) pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -695,6 +726,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -706,6 +738,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; @@ -1065,7 +1098,6 @@ impl parachains_scheduler::Config for Runtime { parameter_types! { pub const BrokerId: u32 = BROKER_ID; pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); - pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000); } pub struct BrokerPot; @@ -1089,7 +1121,6 @@ impl coretime::Config for Runtime { xcm_config::ThisNetwork, ::AccountId, >; - type MaxXcmTransactWeight = MaxXcmTransactWeight; } parameter_types! { @@ -1365,6 +1396,25 @@ impl validator_manager::Config for Runtime { type PrivilegedOrigin = EnsureRoot; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + impl pallet_sudo::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -1497,6 +1547,9 @@ construct_runtime! { Crowdloan: crowdloan = 73, Coretime: coretime = 74, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // Pallet for sending XCM. XcmPallet: pallet_xcm = 99, @@ -1537,8 +1590,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1552,7 +1605,10 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; /// All migrations that will run on the next runtime upgrade. /// @@ -1601,6 +1657,9 @@ pub mod migrations { pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; pub const TipsPalletName: &'static str = "Tips"; 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 @@ -1650,12 +1709,14 @@ 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 pallet_elections_phragmen::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, pallet_democracy::migrations::unlock_and_unreserve_all_funds::UnlockAndUnreserveAllFunds, pallet_tips::migrations::unreserve_deposits::UnreserveDeposits, + pallet_treasury::migration::cleanup_proposals::Migration, // Delete all Gov v1 pallet storage key/values. @@ -1679,7 +1740,8 @@ pub mod migrations { // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, parachains_inclusion::migration::MigrateToV1, - parachains_shared::migration::MigrateToV1, + parachains_shared::migration::MigrateToV1, + parachains_scheduler::migration::MigrateV2ToV3, ); } @@ -1693,7 +1755,7 @@ pub type Executive = frame_executive::Executive< Migrations, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; parameter_types! { // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) @@ -1755,6 +1817,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_parameters, Parameters] @@ -1767,7 +1830,9 @@ mod benches { [pallet_scheduler, Scheduler] [pallet_sudo, Sudo] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -2354,6 +2419,7 @@ sp_api::impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use frame_benchmarking::baseline::Pallet as Baseline; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -2369,11 +2435,12 @@ 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}; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use frame_benchmarking::baseline::Pallet as Baseline; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use sp_storage::TrackedStorageKey; @@ -2586,6 +2653,15 @@ sp_api::impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_teleporter(asset, location) + } + } } #[cfg(all(test, feature = "try-runtime"))] diff --git a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs index dfba0cfc4aa9..0f68a5c6fb37 100644 --- a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs +++ b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `frame_benchmarking::baseline` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=frame_benchmarking::baseline // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/frame_benchmarking_baseline.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,8 +55,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 157_000 picoseconds. - Weight::from_parts(175_233, 0) + // Minimum execution time: 172_000 picoseconds. + Weight::from_parts(199_481, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -61,8 +64,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 149_000 picoseconds. - Weight::from_parts(183_285, 0) + // Minimum execution time: 171_000 picoseconds. + Weight::from_parts(197_821, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -70,8 +73,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 158_000 picoseconds. - Weight::from_parts(184_720, 0) + // Minimum execution time: 172_000 picoseconds. + Weight::from_parts(200_942, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -79,16 +82,16 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 152_000 picoseconds. - Weight::from_parts(177_496, 0) + // Minimum execution time: 170_000 picoseconds. + Weight::from_parts(196_906, 0) .saturating_add(Weight::from_parts(0, 0)) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 19_907_376_000 picoseconds. - Weight::from_parts(19_988_727_000, 0) + // Minimum execution time: 23_346_876_000 picoseconds. + Weight::from_parts(23_363_744_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 100]`. @@ -96,10 +99,10 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 198_000 picoseconds. - Weight::from_parts(228_000, 0) + // Minimum execution time: 201_000 picoseconds. + Weight::from_parts(219_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 20_467 - .saturating_add(Weight::from_parts(47_443_635, 0).saturating_mul(i.into())) + // Standard Error: 14_372 + .saturating_add(Weight::from_parts(45_375_800, 0).saturating_mul(i.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/frame_system.rs b/polkadot/runtime/rococo/src/weights/frame_system.rs index 2e49483dcc62..1742a761ca77 100644 --- a/polkadot/runtime/rococo/src/weights/frame_system.rs +++ b/polkadot/runtime/rococo/src/weights/frame_system.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `frame_system` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=frame_system // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,91 +55,91 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_283_000 picoseconds. - Weight::from_parts(2_305_000, 0) + // Minimum execution time: 1_541_000 picoseconds. + Weight::from_parts(2_581_470, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(366, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_435_000 picoseconds. - Weight::from_parts(7_581_000, 0) + // Minimum execution time: 5_060_000 picoseconds. + Weight::from_parts(5_167_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_408, 0).saturating_mul(b.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_696, 0).saturating_mul(b.into())) } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) - /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) + /// 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: 4_010_000 picoseconds. - Weight::from_parts(4_112_000, 0) + // Minimum execution time: 2_649_000 picoseconds. + Weight::from_parts(2_909_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a636f6465` (r:0 w:1) - /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) + /// 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: `0` // Estimated: `1485` - // Minimum execution time: 80_405_511_000 picoseconds. - Weight::from_parts(83_066_478_000, 0) + // Minimum execution time: 88_417_540_000 picoseconds. + Weight::from_parts(91_809_291_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_210_000 picoseconds. - Weight::from_parts(2_247_000, 0) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_589_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_058 - .saturating_add(Weight::from_parts(673_943, 0).saturating_mul(i.into())) + // Standard Error: 1_740 + .saturating_add(Weight::from_parts(730_941, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_125_000 picoseconds. - Weight::from_parts(2_154_000, 0) + // Minimum execution time: 1_567_000 picoseconds. + Weight::from_parts(1_750_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 816 - .saturating_add(Weight::from_parts(491_194, 0).saturating_mul(i.into())) + // Standard Error: 835 + .saturating_add(Weight::from_parts(543_218, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `129 + p * (69 ±0)` - // Estimated: `125 + p * (70 ±0)` - // Minimum execution time: 4_002_000 picoseconds. - Weight::from_parts(4_145_000, 0) - .saturating_add(Weight::from_parts(0, 125)) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(1_014_971, 0).saturating_mul(p.into())) + // Measured: `80 + p * (69 ±0)` + // Estimated: `83 + p * (70 ±0)` + // Minimum execution time: 3_412_000 picoseconds. + Weight::from_parts(3_448_000, 0) + .saturating_add(Weight::from_parts(0, 83)) + // Standard Error: 1_395 + .saturating_add(Weight::from_parts(1_142_347, 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())) @@ -147,8 +150,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 33_027_000 picoseconds. - Weight::from_parts(33_027_000, 0) + // Minimum execution time: 9_178_000 picoseconds. + Weight::from_parts(9_780_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +165,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `1518` - // Minimum execution time: 118_101_992_000 picoseconds. - Weight::from_parts(118_101_992_000, 0) + // Minimum execution time: 94_523_563_000 picoseconds. + Weight::from_parts(96_983_131_000, 0) .saturating_add(Weight::from_parts(0, 1518)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs b/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..99dac1ba75f0 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,134 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=frame_system_extensions +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 3_262_000 picoseconds. + Weight::from_parts(3_497_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_416_000 picoseconds. + Weight::from_parts(5_690_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 5_416_000 picoseconds. + Weight::from_parts(5_690_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 471_000 picoseconds. + Weight::from_parts(552_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 4_847_000 picoseconds. + Weight::from_parts(5_091_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 388_000 picoseconds. + Weight::from_parts(421_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 378_000 picoseconds. + Weight::from_parts(440_000, 0) + .saturating_add(Weight::from_parts(0, 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: 3_402_000 picoseconds. + Weight::from_parts(3_627_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 020f8e22594a..1c030c444ac5 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -16,6 +16,7 @@ //! A list of the different weight modules for our runtime. pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_asset_rate; pub mod pallet_balances_balances; pub mod pallet_balances_nis_counterpart_balances; @@ -26,6 +27,7 @@ pub mod pallet_conviction_voting; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nis; @@ -39,6 +41,7 @@ pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_sudo; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; diff --git a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs index da2d1958cefc..56b1e2cbc571 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs @@ -16,25 +16,28 @@ //! Autogenerated weights for `pallet_asset_rate` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-03, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `cob`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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/debug/polkadot +// ./target/production/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=2 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_asset_rate // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./runtime/rococo/src/weights/ -// --header=./file_header.txt +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,39 +50,39 @@ use core::marker::PhantomData; /// Weight functions for `pallet_asset_rate`. pub struct WeightInfo(PhantomData); impl pallet_asset_rate::WeightInfo for WeightInfo { - /// Storage: AssetRate ConversionRateToNative (r:1 w:1) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `4702` - // Minimum execution time: 143_000_000 picoseconds. - Weight::from_parts(155_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `142` + // Estimated: `4703` + // Minimum execution time: 10_277_000 picoseconds. + Weight::from_parts(10_487_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:1) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) fn update() -> Weight { // Proof Size summary in bytes: - // Measured: `110` - // Estimated: `4702` - // Minimum execution time: 156_000_000 picoseconds. - Weight::from_parts(172_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `210` + // Estimated: `4703` + // Minimum execution time: 10_917_000 picoseconds. + Weight::from_parts(11_249_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:1) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) fn remove() -> Weight { // Proof Size summary in bytes: - // Measured: `110` - // Estimated: `4702` - // Minimum execution time: 150_000_000 picoseconds. - Weight::from_parts(160_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `210` + // Estimated: `4703` + // Minimum execution time: 11_332_000 picoseconds. + Weight::from_parts(11_866_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs index d37bb9369c68..c3c3315edff2 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs @@ -23,17 +23,19 @@ //! 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_balances // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_balances -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs index 706653aeb769..697e51faf537 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs @@ -23,17 +23,19 @@ //! 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_balances // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_balances -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ diff --git a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs index 38d3645316f2..e1f630ec4ce7 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs @@ -16,25 +16,26 @@ //! Autogenerated weights for `pallet_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-10-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-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 -// --pallet=pallet_bounties // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --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/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,118 +48,195 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bounties`. pub struct WeightInfo(PhantomData); impl pallet_bounties::WeightInfo for WeightInfo { - /// Storage: Bounties BountyCount (r:1 w:1) - /// Proof: Bounties BountyCount (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) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:0 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: `Bounties::BountyCount` (r:1 w:1) + /// Proof: `Bounties::BountyCount` (`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`) + /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) + /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:0 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// The range of component `d` is `[0, 16384]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `210` // Estimated: `3593` - // Minimum execution time: 28_907_000 picoseconds. - Weight::from_parts(31_356_074, 0) + // Minimum execution time: 26_614_000 picoseconds. + Weight::from_parts(28_274_660, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 18 - .saturating_add(Weight::from_parts(606, 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)) } + /// 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() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `302` + // Estimated: `3642` + // 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)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `322` + // Estimated: `3642` + // 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: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `498` + // Estimated: `3642` + // 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)) } + /// 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 accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `494` + // Estimated: `3642` + // 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)) } + /// 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) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `400` + // Estimated: `3642` + // 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)) } + /// 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:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// 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(16400), added: 18875, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `764` + // Estimated: `8799` + // 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)) } - /// 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) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// 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(16400), added: 18875, mode: MaxEncodedLen) + /// 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) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// 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(16400), added: 18875, mode: `MaxEncodedLen`) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `482` + // Measured: `444` // Estimated: `3642` - // Minimum execution time: 46_020_000 picoseconds. - Weight::from_parts(46_711_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)) } + /// 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) + /// 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(16400), added: 18875, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `680` + // Estimated: `6196` + // 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)) } + /// 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: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `358` + // Estimated: `3642` + // 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)) } - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, 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: `Bounties::Bounties` (r:100 w:100) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:200 w:200) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `b` is `[0, 100]`. - fn spend_funds(_b: u32, ) -> Weight { + fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1887` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(2_405_233, 0) + // Measured: `0 + b * (297 ±0)` + // Estimated: `1887 + b * (5206 ±0)` + // Minimum execution time: 3_174_000 picoseconds. + Weight::from_parts(3_336_000, 0) .saturating_add(Weight::from_parts(0, 1887)) + // 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)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs index e8c798d45e72..47ae3a5c90d1 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_child_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_child_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,69 +50,153 @@ use core::marker::PhantomData; /// Weight functions for `pallet_child_bounties`. pub struct WeightInfo(PhantomData); impl pallet_child_bounties::WeightInfo for WeightInfo { + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// 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(16400), added: 18875, 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, 16384]`. - fn add_child_bounty(_d: u32, ) -> Weight { + fn add_child_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `540` + // Estimated: `6196` + // Minimum execution time: 57_964_000 picoseconds. + Weight::from_parts(59_559_565, 0) + .saturating_add(Weight::from_parts(0, 6196)) + // Standard Error: 11 + .saturating_add(Weight::from_parts(697, 0).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `594` + // Estimated: `3642` + // Minimum execution time: 17_527_000 picoseconds. + Weight::from_parts(18_257_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `740` + // Estimated: `3642` + // Minimum execution time: 29_354_000 picoseconds. + Weight::from_parts(30_629_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// 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: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `740` + // Estimated: `3642` + // Minimum execution time: 40_643_000 picoseconds. + Weight::from_parts(42_072_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// 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: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `637` + // Estimated: `3642` + // Minimum execution time: 18_616_000 picoseconds. + Weight::from_parts(19_316_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// 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(16400), added: 18875, mode: `MaxEncodedLen`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `576` + // Estimated: `8799` + // Minimum execution time: 96_376_000 picoseconds. + Weight::from_parts(98_476_000, 0) + .saturating_add(Weight::from_parts(0, 8799)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// 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: `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(16400), added: 18875, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `840` + // Estimated: `6196` + // Minimum execution time: 64_640_000 picoseconds. + Weight::from_parts(66_174_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// 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(16400), added: 18875, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `1027` + // Estimated: `8799` + // Minimum execution time: 78_159_000 picoseconds. + Weight::from_parts(79_820_000, 0) + .saturating_add(Weight::from_parts(0, 8799)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(7)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs index ba505737f1b0..5d92c158df44 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs @@ -16,17 +16,17 @@ //! Autogenerated weights for `pallet_conviction_voting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 // benchmark // pallet -// --chain=kusama-dev +// --chain=rococo-dev // --steps=50 // --repeat=20 // --no-storage-info @@ -36,8 +36,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,144 +50,152 @@ use core::marker::PhantomData; /// Weight functions for `pallet_conviction_voting`. pub struct WeightInfo(PhantomData); impl pallet_conviction_voting::WeightInfo for WeightInfo { - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13445` + // Measured: `13407` // Estimated: `42428` - // Minimum execution time: 151_077_000 picoseconds. - Weight::from_parts(165_283_000, 0) + // Minimum execution time: 128_378_000 picoseconds. + Weight::from_parts(131_028_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `14166` + // Measured: `14128` // Estimated: `83866` - // Minimum execution time: 232_420_000 picoseconds. - Weight::from_parts(244_439_000, 0) + // Minimum execution time: 155_379_000 picoseconds. + Weight::from_parts(161_597_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn remove_vote() -> Weight { // Proof Size summary in bytes: // Measured: `13918` // Estimated: `83866` - // Minimum execution time: 205_017_000 picoseconds. - Weight::from_parts(216_594_000, 0) + // Minimum execution time: 130_885_000 picoseconds. + Weight::from_parts(138_080_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `13004` + // Measured: `13005` // Estimated: `30706` - // Minimum execution time: 84_226_000 picoseconds. - Weight::from_parts(91_255_000, 0) + // Minimum execution time: 71_743_000 picoseconds. + Weight::from_parts(75_170_000, 0) .saturating_add(Weight::from_parts(0, 30706)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: ConvictionVoting VotingFor (r:2 w:2) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:512 w:512) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:50) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 512]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `29640 + r * (365 ±0)` + // Measured: `29602 + r * (365 ±0)` // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 78_708_000 picoseconds. - Weight::from_parts(2_053_488_615, 0) + // Minimum execution time: 58_504_000 picoseconds. + Weight::from_parts(814_301_018, 0) .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 179_271 - .saturating_add(Weight::from_parts(47_806_482, 0).saturating_mul(r.into())) + // Standard Error: 59_961 + .saturating_add(Weight::from_parts(20_002_833, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(45)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) } - /// Storage: ConvictionVoting VotingFor (r:2 w:2) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:512 w:512) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:50) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 512]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `29555 + r * (365 ±0)` // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 45_232_000 picoseconds. - Weight::from_parts(2_045_021_014, 0) + // Minimum execution time: 34_970_000 picoseconds. + Weight::from_parts(771_155_804, 0) .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 185_130 - .saturating_add(Weight::from_parts(47_896_011, 0).saturating_mul(r.into())) + // Standard Error: 57_795 + .saturating_add(Weight::from_parts(19_781_645, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(43)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `12218` + // Measured: `12180` // Estimated: `30706` - // Minimum execution time: 116_446_000 picoseconds. - Weight::from_parts(124_043_000, 0) + // Minimum execution time: 89_648_000 picoseconds. + Weight::from_parts(97_144_000, 0) .saturating_add(Weight::from_parts(0, 30706)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index b334e21ea031..8b0bf7ce826a 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_identity` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_identity // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,290 +50,291 @@ use core::marker::PhantomData; /// Weight functions for `pallet_identity`. pub struct WeightInfo(PhantomData); impl pallet_identity::WeightInfo for WeightInfo { - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 12_290_000 picoseconds. - Weight::from_parts(12_664_362, 0) + // Minimum execution time: 7_673_000 picoseconds. + Weight::from_parts(8_351_866, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_347 - .saturating_add(Weight::from_parts(88_179, 0).saturating_mul(r.into())) + // Standard Error: 1_302 + .saturating_add(Weight::from_parts(79_198, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `442 + r * (5 ±0)` - // Estimated: `11003` - // Minimum execution time: 31_373_000 picoseconds. - Weight::from_parts(30_435_545, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_307 - .saturating_add(Weight::from_parts(92_753, 0).saturating_mul(r.into())) + // Measured: `6978 + r * (5 ±0)` + // Estimated: `11037` + // Minimum execution time: 111_646_000 picoseconds. + Weight::from_parts(113_254_991, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 6_611 + .saturating_add(Weight::from_parts(162_119, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// 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) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11003 + s * (2589 ±0)` - // Minimum execution time: 9_251_000 picoseconds. - Weight::from_parts(22_039_210, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 40_779 - .saturating_add(Weight::from_parts(2_898_525, 0).saturating_mul(s.into())) + // Estimated: `11037 + s * (2589 ±0)` + // Minimum execution time: 8_010_000 picoseconds. + Weight::from_parts(19_868_412, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 5_018 + .saturating_add(Weight::from_parts(3_115_007, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .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(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) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11003` - // Minimum execution time: 9_329_000 picoseconds. - Weight::from_parts(24_055_061, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 3_428 - .saturating_add(Weight::from_parts(1_130_604, 0).saturating_mul(p.into())) + // Estimated: `11037` + // Minimum execution time: 8_111_000 picoseconds. + Weight::from_parts(19_482_392, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 3_156 + .saturating_add(Weight::from_parts(1_305_890, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - /// 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(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) + /// 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`) + /// 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 { + fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 53_365_000 picoseconds. - Weight::from_parts(35_391_422, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_353 - .saturating_add(Weight::from_parts(1_074_019, 0).saturating_mul(s.into())) + // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037` + // Minimum execution time: 54_107_000 picoseconds. + Weight::from_parts(56_347_715, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 10_944 + .saturating_add(Weight::from_parts(191_321, 0).saturating_mul(r.into())) + // Standard Error: 2_135 + .saturating_add(Weight::from_parts(1_295_872, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// 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(7538), added: 10013, mode: MaxEncodedLen) + /// 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`) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `367 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_509_000 picoseconds. - Weight::from_parts(31_745_585, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(83_822, 0).saturating_mul(r.into())) - + // Measured: `6968 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 75_780_000 picoseconds. + Weight::from_parts(76_869_773, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 5_456 + .saturating_add(Weight::from_parts(135_316, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `398 + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 29_609_000 picoseconds. - Weight::from_parts(28_572_602, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_528 - .saturating_add(Weight::from_parts(85_593, 0).saturating_mul(r.into())) + // Measured: `6999` + // Estimated: `11037` + // Minimum execution time: 75_769_000 picoseconds. + Weight::from_parts(76_805_143, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 3_598 + .saturating_add(Weight::from_parts(84_593, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_793_000 picoseconds. - Weight::from_parts(8_173_888, 0) + // Minimum execution time: 5_357_000 picoseconds. + Weight::from_parts(5_732_132, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_569 - .saturating_add(Weight::from_parts(72_367, 0).saturating_mul(r.into())) + // Standard Error: 927 + .saturating_add(Weight::from_parts(70_832, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_708_000 picoseconds. - Weight::from_parts(8_091_149, 0) + // Minimum execution time: 5_484_000 picoseconds. + Weight::from_parts(5_892_704, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 869 - .saturating_add(Weight::from_parts(87_993, 0).saturating_mul(r.into())) + // Standard Error: 947 + .saturating_add(Weight::from_parts(71_231, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_601_000 picoseconds. - Weight::from_parts(8_038_414, 0) + // Minimum execution time: 5_310_000 picoseconds. + Weight::from_parts(5_766_651, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_041 - .saturating_add(Weight::from_parts(82_588, 0).saturating_mul(r.into())) + // Standard Error: 916 + .saturating_add(Weight::from_parts(74_776, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// 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(7538), added: 10013, mode: MaxEncodedLen) + /// 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`) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `445 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 23_114_000 picoseconds. - Weight::from_parts(22_076_548, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_881 - .saturating_add(Weight::from_parts(109_812, 0).saturating_mul(r.into())) + // Measured: `7046 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 98_200_000 picoseconds. + Weight::from_parts(100_105_482, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 6_152 + .saturating_add(Weight::from_parts(58_906, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// 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(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) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, 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::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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) + /// 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 kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 70_007_000 picoseconds. - Weight::from_parts(50_186_495, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 6_533 - .saturating_add(Weight::from_parts(15_486, 0).saturating_mul(r.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(1_085_117, 0).saturating_mul(s.into())) + // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037` + // Minimum execution time: 64_647_000 picoseconds. + Weight::from_parts(68_877_027, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 9_965 + .saturating_add(Weight::from_parts(135_044, 0).saturating_mul(r.into())) + // Standard Error: 1_944 + .saturating_add(Weight::from_parts(1_388_151, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .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(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) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11003` - // Minimum execution time: 28_453_000 picoseconds. - Weight::from_parts(33_165_934, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(65_401, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 23_550_000 picoseconds. + Weight::from_parts(29_439_842, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 1_453 + .saturating_add(Weight::from_parts(96_324, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// 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::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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: `11003` - // Minimum execution time: 12_846_000 picoseconds. - Weight::from_parts(14_710_284, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 496 - .saturating_add(Weight::from_parts(19_539, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 13_704_000 picoseconds. + Weight::from_parts(15_241_441, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 498 + .saturating_add(Weight::from_parts(40_973, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// 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) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_183_000 picoseconds. - Weight::from_parts(35_296_731, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 854 - .saturating_add(Weight::from_parts(52_028, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 29_310_000 picoseconds. + Weight::from_parts(31_712_666, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 967 + .saturating_add(Weight::from_parts(81_250, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// 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) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 24_941_000 picoseconds. - Weight::from_parts(27_433_059, 0) + // Minimum execution time: 22_906_000 picoseconds. + Weight::from_parts(24_638_729, 0) .saturating_add(Weight::from_parts(0, 6723)) - // Standard Error: 856 - .saturating_add(Weight::from_parts(57_463, 0).saturating_mul(s.into())) + // Standard Error: 645 + .saturating_add(Weight::from_parts(75_121, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -340,92 +344,108 @@ impl pallet_identity::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_873_000 picoseconds. - Weight::from_parts(13_873_000, 0) + // Minimum execution time: 6_056_000 picoseconds. + Weight::from_parts(6_349_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) + /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 10_653_000 picoseconds. - Weight::from_parts(10_653_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 9_003_000 picoseconds. + Weight::from_parts(9_276_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// 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(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, 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() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 75_928_000 picoseconds. - Weight::from_parts(75_928_000, 0) + // Minimum execution time: 64_724_000 picoseconds. + Weight::from_parts(66_597_000, 0) .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) + /// 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(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `106` + // Measured: `115` // Estimated: `11037` - // Minimum execution time: 38_157_000 picoseconds. - Weight::from_parts(38_157_000, 0) + // Minimum execution time: 19_538_000 picoseconds. + Weight::from_parts(20_204_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3542` - // Minimum execution time: 46_821_000 picoseconds. - Weight::from_parts(46_821_000, 0) - .saturating_add(Weight::from_parts(0, 3542)) + // Measured: `115` + // Estimated: `3550` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(19_354_000, 0) + .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// 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`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `247` + // Measured: `257` // Estimated: `11037` - // Minimum execution time: 22_515_000 picoseconds. - Weight::from_parts(22_515_000, 0) + // Minimum execution time: 15_298_000 picoseconds. + Weight::from_parts(15_760_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_indices.rs b/polkadot/runtime/rococo/src/weights/pallet_indices.rs index 99ffd3210ed2..434db97d4a79 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_indices.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_indices.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_indices` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_indices // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,66 +50,66 @@ use core::marker::PhantomData; /// Weight functions for `pallet_indices`. pub struct WeightInfo(PhantomData); impl pallet_indices::WeightInfo for WeightInfo { - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn claim() -> Weight { // Proof Size summary in bytes: - // Measured: `142` + // Measured: `4` // Estimated: `3534` - // Minimum execution time: 25_107_000 picoseconds. - Weight::from_parts(25_655_000, 0) + // Minimum execution time: 18_092_000 picoseconds. + Weight::from_parts(18_533_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, 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() -> Weight { // Proof Size summary in bytes: - // Measured: `341` + // Measured: `203` // Estimated: `3593` - // Minimum execution time: 36_208_000 picoseconds. - Weight::from_parts(36_521_000, 0) + // Minimum execution time: 31_616_000 picoseconds. + Weight::from_parts(32_556_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn free() -> Weight { // Proof Size summary in bytes: - // Measured: `238` + // Measured: `100` // Estimated: `3534` - // Minimum execution time: 25_915_000 picoseconds. - Weight::from_parts(26_220_000, 0) + // Minimum execution time: 19_593_000 picoseconds. + Weight::from_parts(20_100_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `341` + // Measured: `203` // Estimated: `3593` - // Minimum execution time: 28_232_000 picoseconds. - Weight::from_parts(28_845_000, 0) + // Minimum execution time: 21_429_000 picoseconds. + Weight::from_parts(22_146_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `238` + // Measured: `100` // Estimated: `3534` - // Minimum execution time: 27_282_000 picoseconds. - Weight::from_parts(27_754_000, 0) + // Minimum execution time: 20_425_000 picoseconds. + Weight::from_parts(21_023_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs b/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs index e1e360d374a0..6ebfcd060b64 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_message_queue` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_message_queue // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,150 +50,149 @@ use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `248` + // Measured: `281` // Estimated: `6050` - // Minimum execution time: 12_106_000 picoseconds. - Weight::from_parts(12_387_000, 0) + // Minimum execution time: 12_830_000 picoseconds. + Weight::from_parts(13_476_000, 0) .saturating_add(Weight::from_parts(0, 6050)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `248` + // Measured: `281` // Estimated: `6050` - // Minimum execution time: 11_227_000 picoseconds. - Weight::from_parts(11_616_000, 0) + // Minimum execution time: 11_583_000 picoseconds. + Weight::from_parts(11_902_000, 0) .saturating_add(Weight::from_parts(0, 6050)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3520` - // Minimum execution time: 5_052_000 picoseconds. - Weight::from_parts(5_216_000, 0) + // Minimum execution time: 3_801_000 picoseconds. + Weight::from_parts(3_943_000, 0) .saturating_add(Weight::from_parts(0, 3520)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `36283` - // Minimum execution time: 6_522_000 picoseconds. - Weight::from_parts(6_794_000, 0) + // Minimum execution time: 5_517_000 picoseconds. + Weight::from_parts(5_861_000, 0) .saturating_add(Weight::from_parts(0, 36283)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `36283` - // Minimum execution time: 6_918_000 picoseconds. - Weight::from_parts(7_083_000, 0) + // Minimum execution time: 5_870_000 picoseconds. + Weight::from_parts(6_028_000, 0) .saturating_add(Weight::from_parts(0, 36283)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 28_445_000 picoseconds. - Weight::from_parts(28_659_000, 0) + // Minimum execution time: 80_681_000 picoseconds. + Weight::from_parts(81_818_000, 0) .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `149` + // Measured: `220` // Estimated: `3520` - // Minimum execution time: 7_224_000 picoseconds. - Weight::from_parts(7_441_000, 0) + // Minimum execution time: 8_641_000 picoseconds. + Weight::from_parts(8_995_000, 0) .saturating_add(Weight::from_parts(0, 3520)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `33232` + // Measured: `32945` // Estimated: `36283` - // Minimum execution time: 45_211_000 picoseconds. - Weight::from_parts(45_505_000, 0) + // Minimum execution time: 38_473_000 picoseconds. + Weight::from_parts(39_831_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `33232` + // Measured: `32945` // Estimated: `36283` - // Minimum execution time: 52_346_000 picoseconds. - Weight::from_parts(52_745_000, 0) + // Minimum execution time: 48_717_000 picoseconds. + Weight::from_parts(49_724_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `33232` + // Measured: `32945` // Estimated: `36283` - // Minimum execution time: 72_567_000 picoseconds. - Weight::from_parts(73_300_000, 0) + // Minimum execution time: 72_718_000 picoseconds. + Weight::from_parts(74_081_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_migrations.rs b/polkadot/runtime/rococo/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..4fa07a23bb8a --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_migrations.rs @@ -0,0 +1,173 @@ +// 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 . + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .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`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_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: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // 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())) + .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()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/polkadot/runtime/rococo/src/weights/pallet_multisig.rs b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs index a4f33fe198ca..f1b81759ece6 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_multisig.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_multisig // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,110 +55,110 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_475_000 picoseconds. - Weight::from_parts(11_904_745, 0) + // Minimum execution time: 12_023_000 picoseconds. + Weight::from_parts(12_643_116, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(492, 0).saturating_mul(z.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(582, 0).saturating_mul(z.into())) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + s * (2 ±0)` + // Measured: `229 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 38_857_000 picoseconds. - Weight::from_parts(33_611_791, 0) + // Minimum execution time: 39_339_000 picoseconds. + Weight::from_parts(27_243_033, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 400 - .saturating_add(Weight::from_parts(59_263, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_211, 0).saturating_mul(z.into())) + // Standard Error: 1_319 + .saturating_add(Weight::from_parts(142_212, 0).saturating_mul(s.into())) + // Standard Error: 12 + .saturating_add(Weight::from_parts(1_592, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `248` // Estimated: `6811` - // Minimum execution time: 25_715_000 picoseconds. - Weight::from_parts(20_607_294, 0) + // Minimum execution time: 27_647_000 picoseconds. + Weight::from_parts(15_828_725, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 285 - .saturating_add(Weight::from_parts(58_225, 0).saturating_mul(s.into())) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_160, 0).saturating_mul(z.into())) + // Standard Error: 908 + .saturating_add(Weight::from_parts(130_880, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_532, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, 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 `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `317 + s * (33 ±0)` + // Measured: `354 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 43_751_000 picoseconds. - Weight::from_parts(37_398_513, 0) + // Minimum execution time: 46_971_000 picoseconds. + Weight::from_parts(32_150_393, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 426 - .saturating_add(Weight::from_parts(70_904, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_235, 0).saturating_mul(z.into())) + // Standard Error: 1_129 + .saturating_add(Weight::from_parts(154_796, 0).saturating_mul(s.into())) + // Standard Error: 11 + .saturating_add(Weight::from_parts(1_603, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + s * (2 ±0)` + // Measured: `229 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 31_278_000 picoseconds. - Weight::from_parts(32_075_573, 0) + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_497_183, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 452 - .saturating_add(Weight::from_parts(62_018, 0).saturating_mul(s.into())) + // Standard Error: 1_615 + .saturating_add(Weight::from_parts(147_071, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `248` // Estimated: `6811` - // Minimum execution time: 18_178_000 picoseconds. - Weight::from_parts(18_649_867, 0) + // Minimum execution time: 13_897_000 picoseconds. + Weight::from_parts(14_828_339, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 293 - .saturating_add(Weight::from_parts(56_475, 0).saturating_mul(s.into())) + // Standard Error: 1_136 + .saturating_add(Weight::from_parts(133_925, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `383 + s * (1 ±0)` + // Measured: `420 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 32_265_000 picoseconds. - Weight::from_parts(32_984_014, 0) + // Minimum execution time: 28_984_000 picoseconds. + Weight::from_parts(29_853_232, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 452 - .saturating_add(Weight::from_parts(59_934, 0).saturating_mul(s.into())) + // Standard Error: 650 + .saturating_add(Weight::from_parts(113_440, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_nis.rs b/polkadot/runtime/rococo/src/weights/pallet_nis.rs index 35dad482129e..38b41f3a8e24 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_nis.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_nis.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_nis` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_nis // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,202 +50,186 @@ use core::marker::PhantomData; /// Weight functions for `pallet_nis`. pub struct WeightInfo(PhantomData); impl pallet_nis::WeightInfo for WeightInfo { - /// 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(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// 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(103), added: 2578, 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]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6209 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 44_704_000 picoseconds. - Weight::from_parts(44_933_886, 0) + // Minimum execution time: 39_592_000 picoseconds. + Weight::from_parts(38_234_037, 0) .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 712 - .saturating_add(Weight::from_parts(71_570, 0).saturating_mul(l.into())) + // Standard Error: 1_237 + .saturating_add(Weight::from_parts(88_816, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// 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(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// 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(103), added: 2578, 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: `54211` // Estimated: `51487` - // Minimum execution time: 126_544_000 picoseconds. - Weight::from_parts(128_271_000, 0) + // Minimum execution time: 134_847_000 picoseconds. + Weight::from_parts(139_510_000, 0) .saturating_add(Weight::from_parts(0, 51487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// 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(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// 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(103), added: 2578, 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]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6209 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_640_000 picoseconds. - Weight::from_parts(42_214_261, 0) + // Minimum execution time: 43_330_000 picoseconds. + Weight::from_parts(35_097_881, 0) .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 732 - .saturating_add(Weight::from_parts(87_277, 0).saturating_mul(l.into())) + // Standard Error: 1_119 + .saturating_add(Weight::from_parts(73_640, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Nis Summary (r:1 w:0) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, 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:0) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `225` // Estimated: `3593` - // Minimum execution time: 38_031_000 picoseconds. - Weight::from_parts(38_441_000, 0) + // Minimum execution time: 29_989_000 picoseconds. + Weight::from_parts(30_865_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// 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(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) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) + /// 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(103), added: 2578, 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) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `469` + // Measured: `387` // Estimated: `3593` - // Minimum execution time: 69_269_000 picoseconds. - Weight::from_parts(70_000_000, 0) + // Minimum execution time: 58_114_000 picoseconds. + Weight::from_parts(59_540_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (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(67), added: 2542, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `659` + // Measured: `543` // Estimated: `3593` - // Minimum execution time: 85_763_000 picoseconds. - Weight::from_parts(86_707_000, 0) + // Minimum execution time: 75_780_000 picoseconds. + Weight::from_parts(77_097_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// 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(67), added: 2542, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// 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(103), added: 2578, mode: `MaxEncodedLen`) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3593` - // Minimum execution time: 47_336_000 picoseconds. - Weight::from_parts(47_623_000, 0) + // Minimum execution time: 46_133_000 picoseconds. + Weight::from_parts(47_250_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, 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::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `604` + // Measured: `488` // Estimated: `3593` - // Minimum execution time: 90_972_000 picoseconds. - Weight::from_parts(92_074_000, 0) + // Minimum execution time: 77_916_000 picoseconds. + Weight::from_parts(79_427_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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 process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6658` // Estimated: `7487` - // Minimum execution time: 21_469_000 picoseconds. - Weight::from_parts(21_983_000, 0) + // Minimum execution time: 22_992_000 picoseconds. + Weight::from_parts(24_112_000, 0) .saturating_add(Weight::from_parts(0, 7487)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: `Nis::Queues` (r:1 w:1) + /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `51487` - // Minimum execution time: 4_912_000 picoseconds. - Weight::from_parts(5_013_000, 0) + // Minimum execution time: 3_856_000 picoseconds. + Weight::from_parts(4_125_000, 0) .saturating_add(Weight::from_parts(0, 51487)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Nis Receipts (r:0 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:0 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) fn process_bid() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_048_000 picoseconds. - Weight::from_parts(7_278_000, 0) + // Minimum execution time: 4_344_000 picoseconds. + Weight::from_parts(4_545_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs index e051ebd5bbab..7a2b77b84d80 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_preimage` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_preimage // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,184 +50,219 @@ use core::marker::PhantomData; /// Weight functions for `pallet_preimage`. pub struct WeightInfo(PhantomData); impl pallet_preimage::WeightInfo for WeightInfo { - fn ensure_updated(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `193 + n * (91 ±0)` - // Estimated: `3593 + n * (2566 ±0)` - // Minimum execution time: 2_000_000 picoseconds. - Weight::from_parts(2_000_000, 3593) - // Standard Error: 13_720 - .saturating_add(Weight::from_parts(17_309_199, 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_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) - } - - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// 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) + /// 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(103), added: 2578, 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: `215` - // Estimated: `3556` - // Minimum execution time: 31_040_000 picoseconds. - Weight::from_parts(31_236_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_974, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `114` + // Estimated: `3568` + // Minimum execution time: 40_363_000 picoseconds. + Weight::from_parts(41_052_000, 0) + .saturating_add(Weight::from_parts(0, 3568)) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_298, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, 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_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 18_025_000 picoseconds. - Weight::from_parts(18_264_000, 0) + // Minimum execution time: 14_570_000 picoseconds. + Weight::from_parts(14_890_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_974, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_364, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, 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_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 17_122_000 picoseconds. - Weight::from_parts(17_332_000, 0) + // Minimum execution time: 13_933_000 picoseconds. + Weight::from_parts(14_290_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_968, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_349, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// 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) + /// 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(103), added: 2578, 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: `361` - // Estimated: `3556` - // Minimum execution time: 38_218_000 picoseconds. - Weight::from_parts(39_841_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `315` + // Estimated: `3568` + // Minimum execution time: 54_373_000 picoseconds. + Weight::from_parts(58_205_000, 0) + .saturating_add(Weight::from_parts(0, 3568)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, 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_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 23_217_000 picoseconds. - Weight::from_parts(24_246_000, 0) + // Minimum execution time: 24_267_000 picoseconds. + Weight::from_parts(27_063_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `260` // Estimated: `3556` - // Minimum execution time: 21_032_000 picoseconds. - Weight::from_parts(21_844_000, 0) + // Minimum execution time: 25_569_000 picoseconds. + Weight::from_parts(27_895_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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) + /// 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: `216` // Estimated: `3556` - // Minimum execution time: 13_954_000 picoseconds. - Weight::from_parts(14_501_000, 0) + // Minimum execution time: 14_182_000 picoseconds. + Weight::from_parts(16_098_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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) + /// 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: `114` // Estimated: `3556` - // Minimum execution time: 14_874_000 picoseconds. - Weight::from_parts(15_380_000, 0) + // Minimum execution time: 14_681_000 picoseconds. + Weight::from_parts(15_549_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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) + /// 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: `178` // Estimated: `3556` - // Minimum execution time: 10_199_000 picoseconds. - Weight::from_parts(10_493_000, 0) + // Minimum execution time: 9_577_000 picoseconds. + Weight::from_parts(10_146_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 21_772_000 picoseconds. - Weight::from_parts(22_554_000, 0) + // Minimum execution time: 21_003_000 picoseconds. + Weight::from_parts(23_549_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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) + /// 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: `178` // Estimated: `3556` - // Minimum execution time: 10_115_000 picoseconds. - Weight::from_parts(10_452_000, 0) + // Minimum execution time: 9_507_000 picoseconds. + Weight::from_parts(10_013_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, 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) + /// 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: `178` // Estimated: `3556` - // Minimum execution time: 10_031_000 picoseconds. - Weight::from_parts(10_310_000, 0) + // Minimum execution time: 9_293_000 picoseconds. + Weight::from_parts(10_055_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Preimage::StatusFor` (r:1023 w:1023) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1023 w:1023) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1023 w:1023) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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: `990 + n * (2603 ±0)` + // Minimum execution time: 48_846_000 picoseconds. + Weight::from_parts(49_378_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 38_493 + .saturating_add(Weight::from_parts(47_418_285, 0).saturating_mul(n.into())) + .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, 2603).saturating_mul(n.into())) + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_proxy.rs b/polkadot/runtime/rococo/src/weights/pallet_proxy.rs index d9737a85c05a..c92025930950 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_proxy.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_proxy.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_proxy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_proxy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,172 +50,176 @@ use core::marker::PhantomData; /// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 15_956_000 picoseconds. - Weight::from_parts(16_300_358, 0) + // Minimum execution time: 11_267_000 picoseconds. + Weight::from_parts(11_798_007, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 652 - .saturating_add(Weight::from_parts(30_807, 0).saturating_mul(p.into())) + // Standard Error: 858 + .saturating_add(Weight::from_parts(43_735, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, 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 `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `554 + a * (68 ±0) + p * (37 ±0)` + // Measured: `416 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 37_584_000 picoseconds. - Weight::from_parts(37_858_207, 0) + // Minimum execution time: 32_791_000 picoseconds. + Weight::from_parts(32_776_904, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_868 - .saturating_add(Weight::from_parts(148_967, 0).saturating_mul(a.into())) - // Standard Error: 1_930 - .saturating_add(Weight::from_parts(13_017, 0).saturating_mul(p.into())) + // Standard Error: 2_382 + .saturating_add(Weight::from_parts(143_857, 0).saturating_mul(a.into())) + // Standard Error: 2_461 + .saturating_add(Weight::from_parts(40_024, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, 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 `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, _p: u32, ) -> Weight { + fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` + // Measured: `331 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 24_642_000 picoseconds. - Weight::from_parts(25_526_588, 0) + // Minimum execution time: 21_831_000 picoseconds. + Weight::from_parts(22_479_938, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_138 - .saturating_add(Weight::from_parts(131_157, 0).saturating_mul(a.into())) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(146_532, 0).saturating_mul(a.into())) + // Standard Error: 1_796 + .saturating_add(Weight::from_parts(7_499, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, 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 `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, _p: u32, ) -> Weight { + fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` + // Measured: `331 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 24_377_000 picoseconds. - Weight::from_parts(25_464_033, 0) + // Minimum execution time: 21_776_000 picoseconds. + Weight::from_parts(22_762_843, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_116 - .saturating_add(Weight::from_parts(130_722, 0).saturating_mul(a.into())) + // Standard Error: 1_402 + .saturating_add(Weight::from_parts(137_512, 0).saturating_mul(a.into())) + // Standard Error: 1_449 + .saturating_add(Weight::from_parts(3_645, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, 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 `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `486 + a * (68 ±0) + p * (37 ±0)` + // Measured: `348 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 34_202_000 picoseconds. - Weight::from_parts(34_610_079, 0) + // Minimum execution time: 29_108_000 picoseconds. + Weight::from_parts(29_508_910, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_234 - .saturating_add(Weight::from_parts(134_197, 0).saturating_mul(a.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(15_970, 0).saturating_mul(p.into())) + // Standard Error: 2_268 + .saturating_add(Weight::from_parts(144_770, 0).saturating_mul(a.into())) + // Standard Error: 2_343 + .saturating_add(Weight::from_parts(25_851, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_492_000 picoseconds. - Weight::from_parts(25_984_867, 0) + // Minimum execution time: 18_942_000 picoseconds. + Weight::from_parts(19_518_812, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 893 - .saturating_add(Weight::from_parts(51_868, 0).saturating_mul(p.into())) + // Standard Error: 1_078 + .saturating_add(Weight::from_parts(46_147, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_492_000 picoseconds. - Weight::from_parts(26_283_445, 0) + // Minimum execution time: 18_993_000 picoseconds. + Weight::from_parts(19_871_741, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_442 - .saturating_add(Weight::from_parts(53_504, 0).saturating_mul(p.into())) + // Standard Error: 1_883 + .saturating_add(Weight::from_parts(46_033, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 22_083_000 picoseconds. - Weight::from_parts(22_688_835, 0) + // Minimum execution time: 17_849_000 picoseconds. + Weight::from_parts(18_776_170, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 994 - .saturating_add(Weight::from_parts(32_994, 0).saturating_mul(p.into())) + // Standard Error: 1_239 + .saturating_add(Weight::from_parts(27_960, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `239` + // Measured: `101` // Estimated: `4706` - // Minimum execution time: 27_042_000 picoseconds. - Weight::from_parts(27_624_587, 0) + // Minimum execution time: 20_049_000 picoseconds. + Weight::from_parts(20_881_515, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 671 - .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(p.into())) + // Standard Error: 952 + .saturating_add(Weight::from_parts(5_970, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `264 + p * (37 ±0)` + // Measured: `126 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 23_396_000 picoseconds. - Weight::from_parts(24_003_080, 0) + // Minimum execution time: 18_528_000 picoseconds. + Weight::from_parts(19_384_189, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 684 - .saturating_add(Weight::from_parts(29_878, 0).saturating_mul(p.into())) + // Standard Error: 1_106 + .saturating_add(Weight::from_parts(35_698, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs index ce9d5fcc0c71..fa2decb16716 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_ranked_collective` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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_ranked_collective // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_ranked_collective -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -60,8 +62,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 13_480_000 picoseconds. - Weight::from_parts(13_786_000, 0) + // Minimum execution time: 13_428_000 picoseconds. + Weight::from_parts(14_019_000, 0) .saturating_add(Weight::from_parts(0, 3507)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) @@ -79,11 +81,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `516 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 28_771_000 picoseconds. - Weight::from_parts(29_256_825, 0) + // Minimum execution time: 28_566_000 picoseconds. + Weight::from_parts(29_346_952, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 21_594 - .saturating_add(Weight::from_parts(14_649_527, 0).saturating_mul(r.into())) + // Standard Error: 21_068 + .saturating_add(Weight::from_parts(14_471_237, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -103,11 +105,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `214 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 16_117_000 picoseconds. - Weight::from_parts(16_978_453, 0) + // Minimum execution time: 16_161_000 picoseconds. + Weight::from_parts(16_981_334, 0) .saturating_add(Weight::from_parts(0, 3507)) - // Standard Error: 4_511 - .saturating_add(Weight::from_parts(324_261, 0).saturating_mul(r.into())) + // Standard Error: 4_596 + .saturating_add(Weight::from_parts(313_386, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -124,11 +126,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `532 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 28_995_000 picoseconds. - Weight::from_parts(31_343_215, 0) + // Minimum execution time: 28_406_000 picoseconds. + Weight::from_parts(31_178_557, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 16_438 - .saturating_add(Weight::from_parts(637_462, 0).saturating_mul(r.into())) + // Standard Error: 17_737 + .saturating_add(Weight::from_parts(627_757, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -140,15 +142,17 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Proof: `FellowshipCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `83866` - // Minimum execution time: 38_820_000 picoseconds. - Weight::from_parts(40_240_000, 0) + // Minimum execution time: 41_164_000 picoseconds. + Weight::from_parts(42_163_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -161,11 +165,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `400 + n * (50 ±0)` // Estimated: `4365 + n * (2540 ±0)` - // Minimum execution time: 12_972_000 picoseconds. - Weight::from_parts(15_829_333, 0) + // Minimum execution time: 13_183_000 picoseconds. + Weight::from_parts(15_604_064, 0) .saturating_add(Weight::from_parts(0, 4365)) - // Standard Error: 1_754 - .saturating_add(Weight::from_parts(1_116_520, 0).saturating_mul(n.into())) + // Standard Error: 2_018 + .saturating_add(Weight::from_parts(1_101_088, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -183,8 +187,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `337` // Estimated: `6048` - // Minimum execution time: 44_601_000 picoseconds. - Weight::from_parts(45_714_000, 0) + // Minimum execution time: 43_603_000 picoseconds. + Weight::from_parts(44_809_000, 0) .saturating_add(Weight::from_parts(0, 6048)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(10)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_recovery.rs b/polkadot/runtime/rococo/src/weights/pallet_recovery.rs new file mode 100644 index 000000000000..ed79aa2b1f17 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_recovery.rs @@ -0,0 +1,186 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_recovery` +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_recovery +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_recovery`. +pub struct WeightInfo(PhantomData); +impl pallet_recovery::WeightInfo for WeightInfo { + /// Storage: `Recovery::Proxy` (r:1 w:0) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + fn as_recovered() -> Weight { + // Proof Size summary in bytes: + // Measured: `215` + // Estimated: `3545` + // Minimum execution time: 7_899_000 picoseconds. + Weight::from_parts(8_205_000, 0) + .saturating_add(Weight::from_parts(0, 3545)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Recovery::Proxy` (r:0 w:1) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + fn set_recovered() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_258_000 picoseconds. + Weight::from_parts(6_494_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:1) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn create_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3816` + // Minimum execution time: 19_369_000 picoseconds. + Weight::from_parts(20_185_132, 0) + .saturating_add(Weight::from_parts(0, 3816)) + // Standard Error: 4_275 + .saturating_add(Weight::from_parts(78_024, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:0) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + fn initiate_recovery() -> Weight { + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `3854` + // Minimum execution time: 22_425_000 picoseconds. + Weight::from_parts(23_171_000, 0) + .saturating_add(Weight::from_parts(0, 3854)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:0) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn vouch_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `294 + n * (64 ±0)` + // Estimated: `3854` + // Minimum execution time: 17_308_000 picoseconds. + Weight::from_parts(18_118_782, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 4_309 + .saturating_add(Weight::from_parts(126_278, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:0) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: `Recovery::Proxy` (r:1 w:1) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn claim_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `326 + n * (64 ±0)` + // Estimated: `3854` + // Minimum execution time: 20_755_000 picoseconds. + Weight::from_parts(21_821_713, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 4_550 + .saturating_add(Weight::from_parts(101_916, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, 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 `n` is `[1, 9]`. + fn close_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `447 + n * (32 ±0)` + // Estimated: `3854` + // Minimum execution time: 29_957_000 picoseconds. + Weight::from_parts(31_010_309, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 5_913 + .saturating_add(Weight::from_parts(110_070, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: `Recovery::Recoverable` (r:1 w:1) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn remove_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `204 + n * (32 ±0)` + // Estimated: `3854` + // Minimum execution time: 24_430_000 picoseconds. + Weight::from_parts(24_462_856, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 13_646 + .saturating_add(Weight::from_parts(507_715, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Proxy` (r:1 w:1) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + fn cancel_recovered() -> Weight { + // Proof Size summary in bytes: + // Measured: `215` + // Estimated: `3545` + // Minimum execution time: 9_686_000 picoseconds. + Weight::from_parts(10_071_000, 0) + .saturating_add(Weight::from_parts(0, 3545)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs index 96f172230e13..6dfcea2b8327 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs @@ -16,27 +16,28 @@ //! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_referenda -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,10 +60,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `327` + // Measured: `292` // Estimated: `42428` - // Minimum execution time: 29_909_000 picoseconds. - Weight::from_parts(30_645_000, 0) + // Minimum execution time: 24_053_000 picoseconds. + Weight::from_parts(25_121_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -71,15 +72,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `403` // Estimated: `83866` - // Minimum execution time: 54_405_000 picoseconds. - Weight::from_parts(55_583_000, 0) + // Minimum execution time: 45_064_000 picoseconds. + Weight::from_parts(46_112_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -89,15 +92,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2076` + // Measured: `2041` // Estimated: `42428` - // Minimum execution time: 110_477_000 picoseconds. - Weight::from_parts(119_187_000, 0) + // Minimum execution time: 94_146_000 picoseconds. + Weight::from_parts(98_587_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -107,15 +112,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2117` + // Measured: `2082` // Estimated: `42428` - // Minimum execution time: 111_467_000 picoseconds. - Weight::from_parts(117_758_000, 0) + // Minimum execution time: 93_002_000 picoseconds. + Weight::from_parts(96_924_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -125,15 +132,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `774` + // Measured: `739` // Estimated: `83866` - // Minimum execution time: 191_135_000 picoseconds. - Weight::from_parts(210_535_000, 0) + // Minimum execution time: 160_918_000 picoseconds. + Weight::from_parts(175_603_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -143,24 +152,26 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `639` + // Measured: `604` // Estimated: `83866` - // Minimum execution time: 67_168_000 picoseconds. - Weight::from_parts(68_895_000, 0) + // Minimum execution time: 55_253_000 picoseconds. + Weight::from_parts(56_488_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `351` + // Measured: `317` // Estimated: `4365` - // Minimum execution time: 31_298_000 picoseconds. - Weight::from_parts(32_570_000, 0) + // Minimum execution time: 24_497_000 picoseconds. + Weight::from_parts(25_280_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -169,10 +180,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `201` + // Measured: `167` // Estimated: `4365` - // Minimum execution time: 15_674_000 picoseconds. - Weight::from_parts(16_190_000, 0) + // Minimum execution time: 11_374_000 picoseconds. + Weight::from_parts(11_817_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -181,15 +192,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `348` // Estimated: `83866` - // Minimum execution time: 38_927_000 picoseconds. - Weight::from_parts(40_545_000, 0) + // Minimum execution time: 31_805_000 picoseconds. + Weight::from_parts(32_622_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -197,15 +210,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `FellowshipReferenda::MetadataOf` (r:1 w:0) /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `484` + // Measured: `449` // Estimated: `83866` - // Minimum execution time: 80_209_000 picoseconds. - Weight::from_parts(82_084_000, 0) + // Minimum execution time: 62_364_000 picoseconds. + Weight::from_parts(63_798_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:0) /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) @@ -213,10 +228,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `174` + // Measured: `140` // Estimated: `4277` - // Minimum execution time: 9_520_000 picoseconds. - Weight::from_parts(10_088_000, 0) + // Minimum execution time: 8_811_000 picoseconds. + Weight::from_parts(9_224_000, 0) .saturating_add(Weight::from_parts(0, 4277)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -231,10 +246,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `2376` + // Measured: `2341` // Estimated: `42428` - // Minimum execution time: 93_893_000 picoseconds. - Weight::from_parts(101_065_000, 0) + // Minimum execution time: 83_292_000 picoseconds. + Weight::from_parts(89_114_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -249,10 +264,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `2362` + // Measured: `2327` // Estimated: `42428` - // Minimum execution time: 98_811_000 picoseconds. - Weight::from_parts(103_590_000, 0) + // Minimum execution time: 84_648_000 picoseconds. + Weight::from_parts(89_332_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -263,10 +278,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `1841` + // Measured: `1807` // Estimated: `4365` - // Minimum execution time: 43_230_000 picoseconds. - Weight::from_parts(46_120_000, 0) + // Minimum execution time: 40_529_000 picoseconds. + Weight::from_parts(45_217_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -277,10 +292,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `1808` + // Measured: `1774` // Estimated: `4365` - // Minimum execution time: 43_092_000 picoseconds. - Weight::from_parts(46_018_000, 0) + // Minimum execution time: 40_894_000 picoseconds. + Weight::from_parts(45_726_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -293,10 +308,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1824` + // Measured: `1790` // Estimated: `4365` - // Minimum execution time: 49_697_000 picoseconds. - Weight::from_parts(53_795_000, 0) + // Minimum execution time: 48_187_000 picoseconds. + Weight::from_parts(52_655_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -309,10 +324,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1865` + // Measured: `1831` // Estimated: `4365` - // Minimum execution time: 50_417_000 picoseconds. - Weight::from_parts(53_214_000, 0) + // Minimum execution time: 47_548_000 picoseconds. + Weight::from_parts(51_547_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -323,10 +338,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `300` // Estimated: `42428` - // Minimum execution time: 25_688_000 picoseconds. - Weight::from_parts(26_575_000, 0) + // Minimum execution time: 20_959_000 picoseconds. + Weight::from_parts(21_837_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -337,10 +352,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `348` // Estimated: `42428` - // Minimum execution time: 26_230_000 picoseconds. - Weight::from_parts(27_235_000, 0) + // Minimum execution time: 21_628_000 picoseconds. + Weight::from_parts(22_192_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -349,10 +364,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `208` // Estimated: `4365` - // Minimum execution time: 17_585_000 picoseconds. - Weight::from_parts(18_225_000, 0) + // Minimum execution time: 12_309_000 picoseconds. + Weight::from_parts(12_644_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,10 +382,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `584` + // Measured: `549` // Estimated: `42428` - // Minimum execution time: 38_243_000 picoseconds. - Weight::from_parts(39_959_000, 0) + // Minimum execution time: 31_871_000 picoseconds. + Weight::from_parts(33_123_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -385,10 +400,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `719` + // Measured: `684` // Estimated: `42428` - // Minimum execution time: 88_424_000 picoseconds. - Weight::from_parts(92_969_000, 0) + // Minimum execution time: 73_715_000 picoseconds. + Weight::from_parts(79_980_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -401,10 +416,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `770` + // Measured: `735` // Estimated: `42428` - // Minimum execution time: 138_207_000 picoseconds. - Weight::from_parts(151_726_000, 0) + // Minimum execution time: 128_564_000 picoseconds. + Weight::from_parts(138_536_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -417,10 +432,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `755` + // Measured: `720` // Estimated: `42428` - // Minimum execution time: 131_001_000 picoseconds. - Weight::from_parts(148_651_000, 0) + // Minimum execution time: 129_775_000 picoseconds. + Weight::from_parts(139_001_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -433,10 +448,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `770` + // Measured: `735` // Estimated: `42428` - // Minimum execution time: 109_612_000 picoseconds. - Weight::from_parts(143_626_000, 0) + // Minimum execution time: 128_233_000 picoseconds. + Weight::from_parts(135_796_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -449,10 +464,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `776` + // Measured: `741` // Estimated: `42428` - // Minimum execution time: 71_754_000 picoseconds. - Weight::from_parts(77_329_000, 0) + // Minimum execution time: 66_995_000 picoseconds. + Weight::from_parts(72_678_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -467,10 +482,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `776` + // Measured: `741` // Estimated: `83866` - // Minimum execution time: 153_244_000 picoseconds. - Weight::from_parts(169_961_000, 0) + // Minimum execution time: 137_764_000 picoseconds. + Weight::from_parts(152_260_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -483,10 +498,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `772` + // Measured: `737` // Estimated: `42428` - // Minimum execution time: 137_997_000 picoseconds. - Weight::from_parts(157_862_000, 0) + // Minimum execution time: 119_992_000 picoseconds. + Weight::from_parts(134_805_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -495,16 +510,18 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `FellowshipReferenda::MetadataOf` (r:0 w:1) /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `458` + // Measured: `424` // Estimated: `4365` - // Minimum execution time: 21_794_000 picoseconds. - Weight::from_parts(22_341_000, 0) + // Minimum execution time: 20_927_000 picoseconds. + Weight::from_parts(21_802_000, 0) .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) @@ -513,10 +530,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `319` + // Measured: `285` // Estimated: `4365` - // Minimum execution time: 18_458_000 picoseconds. - Weight::from_parts(19_097_000, 0) + // Minimum execution time: 14_253_000 picoseconds. + Weight::from_parts(15_031_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs index b7cc5df28b91..c35925198f9d 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs @@ -16,27 +16,28 @@ //! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_referenda -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,10 +58,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `324` + // Measured: `185` // Estimated: `42428` - // Minimum execution time: 39_852_000 picoseconds. - Weight::from_parts(41_610_000, 0) + // Minimum execution time: 28_612_000 picoseconds. + Weight::from_parts(30_060_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -69,15 +70,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `577` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 52_588_000 picoseconds. - Weight::from_parts(54_154_000, 0) + // Minimum execution time: 42_827_000 picoseconds. + Weight::from_parts(44_072_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -87,15 +90,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3334` + // Measured: `3225` // Estimated: `42428` - // Minimum execution time: 70_483_000 picoseconds. - Weight::from_parts(72_731_000, 0) + // Minimum execution time: 56_475_000 picoseconds. + Weight::from_parts(58_888_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -105,60 +110,62 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3354` + // Measured: `3245` // Estimated: `42428` - // Minimum execution time: 68_099_000 picoseconds. - Weight::from_parts(71_560_000, 0) + // Minimum execution time: 56_542_000 picoseconds. + Weight::from_parts(58_616_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `577` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 64_357_000 picoseconds. - Weight::from_parts(66_081_000, 0) + // Minimum execution time: 51_218_000 picoseconds. + Weight::from_parts(53_148_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `577` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 62_709_000 picoseconds. - Weight::from_parts(64_534_000, 0) + // Minimum execution time: 49_097_000 picoseconds. + Weight::from_parts(50_796_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `279` // Estimated: `4401` - // Minimum execution time: 31_296_000 picoseconds. - Weight::from_parts(32_221_000, 0) + // Minimum execution time: 23_720_000 picoseconds. + Weight::from_parts(24_327_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -167,10 +174,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `407` + // Measured: `269` // Estimated: `4401` - // Minimum execution time: 31_209_000 picoseconds. - Weight::from_parts(32_168_000, 0) + // Minimum execution time: 24_089_000 picoseconds. + Weight::from_parts(24_556_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -179,15 +186,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `83866` - // Minimum execution time: 38_887_000 picoseconds. - Weight::from_parts(40_193_000, 0) + // Minimum execution time: 29_022_000 picoseconds. + Weight::from_parts(29_590_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -195,15 +204,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Referenda::MetadataOf` (r:1 w:0) /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `726` + // Measured: `587` // Estimated: `83866` - // Minimum execution time: 106_054_000 picoseconds. - Weight::from_parts(108_318_000, 0) + // Minimum execution time: 81_920_000 picoseconds. + Weight::from_parts(84_492_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::TrackQueue` (r:1 w:0) /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) @@ -211,10 +222,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `240` + // Measured: `102` // Estimated: `5477` - // Minimum execution time: 9_263_000 picoseconds. - Weight::from_parts(9_763_000, 0) + // Minimum execution time: 8_134_000 picoseconds. + Weight::from_parts(8_574_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -223,36 +234,32 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3254` + // Measured: `3115` // Estimated: `42428` - // Minimum execution time: 50_080_000 picoseconds. - Weight::from_parts(51_858_000, 0) + // Minimum execution time: 39_932_000 picoseconds. + Weight::from_parts(42_086_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::TrackQueue` (r:1 w:1) /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3254` + // Measured: `3115` // Estimated: `42428` - // Minimum execution time: 53_889_000 picoseconds. - Weight::from_parts(55_959_000, 0) + // Minimum execution time: 42_727_000 picoseconds. + Weight::from_parts(44_280_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) @@ -261,10 +268,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `2939` // Estimated: `5477` - // Minimum execution time: 23_266_000 picoseconds. - Weight::from_parts(24_624_000, 0) + // Minimum execution time: 20_918_000 picoseconds. + Weight::from_parts(22_180_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -275,10 +282,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `2939` // Estimated: `5477` - // Minimum execution time: 22_846_000 picoseconds. - Weight::from_parts(24_793_000, 0) + // Minimum execution time: 20_943_000 picoseconds. + Weight::from_parts(21_932_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -291,10 +298,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3081` + // Measured: `2943` // Estimated: `5477` - // Minimum execution time: 28_284_000 picoseconds. - Weight::from_parts(29_940_000, 0) + // Minimum execution time: 25_197_000 picoseconds. + Weight::from_parts(26_083_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -307,10 +314,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3101` + // Measured: `2963` // Estimated: `5477` - // Minimum execution time: 28_133_000 picoseconds. - Weight::from_parts(29_638_000, 0) + // Minimum execution time: 24_969_000 picoseconds. + Weight::from_parts(26_096_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -321,10 +328,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `437` + // Measured: `298` // Estimated: `42428` - // Minimum execution time: 25_710_000 picoseconds. - Weight::from_parts(26_500_000, 0) + // Minimum execution time: 18_050_000 picoseconds. + Weight::from_parts(18_790_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -335,10 +342,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `42428` - // Minimum execution time: 25_935_000 picoseconds. - Weight::from_parts(26_803_000, 0) + // Minimum execution time: 18_357_000 picoseconds. + Weight::from_parts(18_957_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -347,10 +354,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `206` // Estimated: `4401` - // Minimum execution time: 17_390_000 picoseconds. - Weight::from_parts(18_042_000, 0) + // Minimum execution time: 11_479_000 picoseconds. + Weight::from_parts(11_968_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -359,150 +366,136 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `42428` - // Minimum execution time: 35_141_000 picoseconds. - Weight::from_parts(36_318_000, 0) + // Minimum execution time: 24_471_000 picoseconds. + Weight::from_parts(25_440_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `42428` - // Minimum execution time: 37_815_000 picoseconds. - Weight::from_parts(39_243_000, 0) + // Minimum execution time: 26_580_000 picoseconds. + Weight::from_parts(27_570_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `538` + // Measured: `399` // Estimated: `42428` - // Minimum execution time: 30_779_000 picoseconds. - Weight::from_parts(31_845_000, 0) + // Minimum execution time: 24_331_000 picoseconds. + Weight::from_parts(25_291_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `521` + // Measured: `382` // Estimated: `42428` - // Minimum execution time: 31_908_000 picoseconds. - Weight::from_parts(33_253_000, 0) + // Minimum execution time: 24_768_000 picoseconds. + Weight::from_parts(25_746_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `538` + // Measured: `399` // Estimated: `42428` - // Minimum execution time: 28_951_000 picoseconds. - Weight::from_parts(30_004_000, 0) + // Minimum execution time: 23_171_000 picoseconds. + Weight::from_parts(24_161_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `542` + // Measured: `403` // Estimated: `42428` - // Minimum execution time: 27_750_000 picoseconds. - Weight::from_parts(28_588_000, 0) + // Minimum execution time: 22_263_000 picoseconds. + Weight::from_parts(23_062_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `542` + // Measured: `403` // Estimated: `83866` - // Minimum execution time: 43_950_000 picoseconds. - Weight::from_parts(46_164_000, 0) + // Minimum execution time: 33_710_000 picoseconds. + Weight::from_parts(34_871_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `538` + // Measured: `399` // Estimated: `42428` - // Minimum execution time: 31_050_000 picoseconds. - Weight::from_parts(32_169_000, 0) + // Minimum execution time: 24_260_000 picoseconds. + Weight::from_parts(25_104_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, 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:0) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Referenda::MetadataOf` (r:0 w:1) /// 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: `560` + // Measured: `422` // Estimated: `4401` - // Minimum execution time: 21_193_000 picoseconds. - Weight::from_parts(22_116_000, 0) + // Minimum execution time: 19_821_000 picoseconds. + Weight::from_parts(20_641_000, 0) .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) @@ -511,10 +504,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `283` // Estimated: `4401` - // Minimum execution time: 18_065_000 picoseconds. - Weight::from_parts(18_781_000, 0) + // Minimum execution time: 13_411_000 picoseconds. + Weight::from_parts(14_070_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs index 0f36dbd384df..5f6b41d2b54e 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_scheduler` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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_scheduler // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_scheduler -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -54,8 +56,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68` // Estimated: `1489` - // Minimum execution time: 2_869_000 picoseconds. - Weight::from_parts(3_109_000, 0) + // Minimum execution time: 3_114_000 picoseconds. + Weight::from_parts(3_245_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -67,11 +69,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 3_326_000 picoseconds. - Weight::from_parts(5_818_563, 0) + // Minimum execution time: 3_430_000 picoseconds. + Weight::from_parts(6_250_920, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_261 - .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(s.into())) + // Standard Error: 1_350 + .saturating_add(Weight::from_parts(333_245, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -79,8 +81,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_007_000 picoseconds. - Weight::from_parts(3_197_000, 0) + // Minimum execution time: 3_166_000 picoseconds. + Weight::from_parts(3_295_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) @@ -94,11 +96,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `251 + s * (1 ±0)` // Estimated: `3716 + s * (1 ±0)` - // Minimum execution time: 16_590_000 picoseconds. - Weight::from_parts(16_869_000, 0) + // Minimum execution time: 17_072_000 picoseconds. + Weight::from_parts(17_393_000, 0) .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_308, 0).saturating_mul(s.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -109,8 +111,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_320_000 picoseconds. - Weight::from_parts(4_594_000, 0) + // Minimum execution time: 4_566_000 picoseconds. + Weight::from_parts(4_775_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,24 +120,24 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_956_000 picoseconds. - Weight::from_parts(3_216_000, 0) + // Minimum execution time: 3_180_000 picoseconds. + Weight::from_parts(3_339_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_929_000, 0) + // Minimum execution time: 1_656_000 picoseconds. + Weight::from_parts(1_829_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_749_000 picoseconds. - Weight::from_parts(1_916_000, 0) + // Minimum execution time: 1_628_000 picoseconds. + Weight::from_parts(1_840_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) @@ -145,16 +147,18 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 9_086_000 picoseconds. - Weight::from_parts(11_733_696, 0) + // Minimum execution time: 9_523_000 picoseconds. + Weight::from_parts(12_482_434, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_362 - .saturating_add(Weight::from_parts(375_266, 0).saturating_mul(s.into())) + // Standard Error: 1_663 + .saturating_add(Weight::from_parts(370_122, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. @@ -162,13 +166,13 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 12_716_000 picoseconds. - Weight::from_parts(12_529_180, 0) + // Minimum execution time: 14_649_000 picoseconds. + Weight::from_parts(14_705_132, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 867 - .saturating_add(Weight::from_parts(548_188, 0).saturating_mul(s.into())) + // Standard Error: 1_126 + .saturating_add(Weight::from_parts(547_438, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -179,11 +183,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 12_053_000 picoseconds. - Weight::from_parts(15_358_056, 0) + // Minimum execution time: 12_335_000 picoseconds. + Weight::from_parts(16_144_217, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 3_176 - .saturating_add(Weight::from_parts(421_589, 0).saturating_mul(s.into())) + // Standard Error: 3_533 + .saturating_add(Weight::from_parts(413_823, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -191,49 +195,48 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `318 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 14_803_000 picoseconds. - Weight::from_parts(15_805_714, 0) + // Minimum execution time: 16_906_000 picoseconds. + Weight::from_parts(17_846_662, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_597 - .saturating_add(Weight::from_parts(611_053, 0).saturating_mul(s.into())) + // Standard Error: 2_687 + .saturating_add(Weight::from_parts(613_356, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Scheduler::Retries` (r:1 w:2) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Lookup` (r:0 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. fn schedule_retry(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `196` + // Measured: `155` // Estimated: `42428` - // Minimum execution time: 13_156_000 picoseconds. - Weight::from_parts(13_801_287, 0) + // Minimum execution time: 8_988_000 picoseconds. + Weight::from_parts(9_527_838, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 568 - .saturating_add(Weight::from_parts(35_441, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) + // Standard Error: 523 + .saturating_add(Weight::from_parts(25_453, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Scheduler::Agenda` (r:1 w:0) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn set_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `115 + s * (177 ±0)` + // Measured: `8965` // Estimated: `42428` - // Minimum execution time: 7_912_000 picoseconds. - Weight::from_parts(8_081_460, 0) + // Minimum execution time: 23_337_000 picoseconds. + Weight::from_parts(24_255_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -244,13 +247,12 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn set_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `324 + s * (185 ±0)` + // Measured: `9643` // Estimated: `42428` - // Minimum execution time: 10_673_000 picoseconds. - Weight::from_parts(12_212_185, 0) + // Minimum execution time: 30_704_000 picoseconds. + Weight::from_parts(31_646_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -259,13 +261,12 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn cancel_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `115 + s * (177 ±0)` + // Measured: `8977` // Estimated: `42428` - // Minimum execution time: 7_912_000 picoseconds. - Weight::from_parts(8_081_460, 0) + // Minimum execution time: 22_279_000 picoseconds. + Weight::from_parts(23_106_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -276,13 +277,12 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn cancel_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `324 + s * (185 ±0)` + // Measured: `9655` // Estimated: `42428` - // Minimum execution time: 10_673_000 picoseconds. - Weight::from_parts(12_212_185, 0) + // Minimum execution time: 29_649_000 picoseconds. + Weight::from_parts(30_472_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs index 694174954fc7..ecc31dc3fa9d 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_sudo` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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_sudo // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_sudo -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -54,8 +56,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 8_432_000 picoseconds. - Weight::from_parts(8_757_000, 0) + // Minimum execution time: 8_336_000 picoseconds. + Weight::from_parts(8_569_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -66,8 +68,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 9_167_000 picoseconds. - Weight::from_parts(9_397_000, 0) + // Minimum execution time: 8_858_000 picoseconds. + Weight::from_parts(9_238_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -77,8 +79,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 9_133_000 picoseconds. - Weight::from_parts(9_573_000, 0) + // Minimum execution time: 8_921_000 picoseconds. + Weight::from_parts(9_324_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -88,10 +90,21 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 7_374_000 picoseconds. - Weight::from_parts(7_702_000, 0) + // Minimum execution time: 7_398_000 picoseconds. + Weight::from_parts(7_869_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Sudo::Key` (r:1 w:0) + /// 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: `132` + // Estimated: `1517` + // Minimum execution time: 3_146_000 picoseconds. + Weight::from_parts(3_314_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs b/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs index 1bb2e227ab7d..7d79621b9e65 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_timestamp // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,26 +50,26 @@ use core::marker::PhantomData; /// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: Timestamp Now (r:1 w:1) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe CurrentSlot (r:1 w:0) - /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Babe::CurrentSlot` (r:1 w:0) + /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `137` // Estimated: `1493` - // Minimum execution time: 10_103_000 picoseconds. - Weight::from_parts(10_597_000, 0) + // Minimum execution time: 5_596_000 picoseconds. + Weight::from_parts(5_823_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `94` + // Measured: `57` // Estimated: `0` - // Minimum execution time: 4_718_000 picoseconds. - Weight::from_parts(4_839_000, 0) + // Minimum execution time: 2_777_000 picoseconds. + Weight::from_parts(2_900_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs b/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..44dfab289fb2 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,68 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_transaction_payment +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// 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`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `1737` + // Minimum execution time: 33_070_000 picoseconds. + Weight::from_parts(33_730_000, 0) + .saturating_add(Weight::from_parts(0, 1737)) + .saturating_add(T::DbWeight::get().reads(3)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs index 06246ada72f1..42d7b2607645 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs @@ -16,25 +16,28 @@ //! Autogenerated weights for `pallet_treasury` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `cob`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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/debug/polkadot +// ./target/production/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=2 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_treasury // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./runtime/rococo/src/weights/ -// --header=./file_header.txt +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,18 +50,18 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, 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:0 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: `Treasury::ProposalCount` (r:1 w:1) + /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, 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:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn spend_local() -> Weight { // Proof Size summary in bytes: - // Measured: `42` + // Measured: `142` // Estimated: `1887` - // Minimum execution time: 177_000_000 picoseconds. - Weight::from_parts(191_000_000, 0) + // Minimum execution time: 9_928_000 picoseconds. + Weight::from_parts(10_560_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -67,111 +70,103 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// 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: `127` + // Measured: `227` // Estimated: `1887` - // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(82_000_000, 0) + // Minimum execution time: 5_386_000 picoseconds. + Weight::from_parts(5_585_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Treasury Deactivated (r:1 w:1) - /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (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:199 w:199) - /// 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::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:199 w:199) + /// 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`) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `331 + p * (251 ±0)` + // Measured: `431 + p * (251 ±0)` // Estimated: `3593 + p * (5206 ±0)` - // Minimum execution time: 887_000_000 picoseconds. - Weight::from_parts(828_616_021, 0) + // Minimum execution time: 43_737_000 picoseconds. + Weight::from_parts(39_883_021, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 695_351 - .saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Standard Error: 12_917 + .saturating_add(Weight::from_parts(31_796_205, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:0) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, 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(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, 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(1853), added: 4328, mode: `MaxEncodedLen`) fn spend() -> Weight { // Proof Size summary in bytes: - // Measured: `114` - // Estimated: `4702` - // Minimum execution time: 208_000_000 picoseconds. - Weight::from_parts(222_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `215` + // Estimated: `4703` + // Minimum execution time: 16_829_000 picoseconds. + Weight::from_parts(17_251_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Treasury Spends (r:1 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) - /// Storage: XcmPallet QueryCounter (r:1 w:1) - /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// 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 Queries (r:0 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) + /// Proof: `XcmPallet::QueryCounter` (`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: `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 payout() -> Weight { // Proof Size summary in bytes: - // Measured: `737` - // Estimated: `5313` - // Minimum execution time: 551_000_000 picoseconds. - Weight::from_parts(569_000_000, 0) - .saturating_add(Weight::from_parts(0, 5313)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `458` + // Estimated: `5318` + // Minimum execution time: 41_554_000 picoseconds. + Weight::from_parts(42_451_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Treasury Spends (r:1 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) - /// Storage: XcmPallet Queries (r:1 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::Queries` (r:1 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `442` - // Estimated: `5313` - // Minimum execution time: 245_000_000 picoseconds. - Weight::from_parts(281_000_000, 0) - .saturating_add(Weight::from_parts(0, 5313)) + // Measured: `306` + // Estimated: `5318` + // Minimum execution time: 22_546_000 picoseconds. + Weight::from_parts(23_151_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Treasury Spends (r:1 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `172` - // Estimated: `5313` - // Minimum execution time: 147_000_000 picoseconds. - Weight::from_parts(160_000_000, 0) - .saturating_add(Weight::from_parts(0, 5313)) + // Measured: `278` + // Estimated: `5318` + // Minimum execution time: 12_169_000 picoseconds. + Weight::from_parts(12_484_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_utility.rs b/polkadot/runtime/rococo/src/weights/pallet_utility.rs index f50f60eaad7f..6f2a374247f8 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_utility.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_utility.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_utility // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,18 +55,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_738_000 picoseconds. - Weight::from_parts(2_704_821, 0) + // Minimum execution time: 4_041_000 picoseconds. + Weight::from_parts(5_685_496, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_999 - .saturating_add(Weight::from_parts(4_627_278, 0).saturating_mul(c.into())) + // Standard Error: 810 + .saturating_add(Weight::from_parts(3_177_197, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_294_000 picoseconds. - Weight::from_parts(5_467_000, 0) + // Minimum execution time: 3_667_000 picoseconds. + Weight::from_parts(3_871_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +74,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_828_000 picoseconds. - Weight::from_parts(4_650_678, 0) + // Minimum execution time: 4_116_000 picoseconds. + Weight::from_parts(6_453_932, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_789 - .saturating_add(Weight::from_parts(4_885_004, 0).saturating_mul(c.into())) + // Standard Error: 825 + .saturating_add(Weight::from_parts(3_366_112, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_020_000 picoseconds. - Weight::from_parts(9_205_000, 0) + // Minimum execution time: 5_630_000 picoseconds. + Weight::from_parts(5_956_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +93,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_852_000 picoseconds. - Weight::from_parts(20_703_134, 0) + // Minimum execution time: 4_165_000 picoseconds. + Weight::from_parts(5_442_561, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_924 - .saturating_add(Weight::from_parts(4_604_529, 0).saturating_mul(c.into())) + // Standard Error: 460 + .saturating_add(Weight::from_parts(3_173_577, 0).saturating_mul(c.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs index 2596207d5837..c21ab0877742 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_vesting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_vesting // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,143 +50,143 @@ use core::marker::PhantomData; /// Weight functions for `pallet_vesting`. pub struct WeightInfo(PhantomData); impl pallet_vesting::WeightInfo for WeightInfo { - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `277 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 32_820_000 picoseconds. - Weight::from_parts(31_640_992, 0) + // Minimum execution time: 29_288_000 picoseconds. + Weight::from_parts(29_095_507, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 449 - .saturating_add(Weight::from_parts(45_254, 0).saturating_mul(l.into())) - // Standard Error: 800 - .saturating_add(Weight::from_parts(72_178, 0).saturating_mul(s.into())) + // Standard Error: 1_679 + .saturating_add(Weight::from_parts(33_164, 0).saturating_mul(l.into())) + // Standard Error: 2_988 + .saturating_add(Weight::from_parts(67_092, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `277 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_054_000 picoseconds. - Weight::from_parts(35_825_428, 0) + // Minimum execution time: 31_003_000 picoseconds. + Weight::from_parts(30_528_438, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 749 - .saturating_add(Weight::from_parts(31_738, 0).saturating_mul(l.into())) - // Standard Error: 1_333 - .saturating_add(Weight::from_parts(40_580, 0).saturating_mul(s.into())) + // Standard Error: 1_586 + .saturating_add(Weight::from_parts(35_429, 0).saturating_mul(l.into())) + // Standard Error: 2_823 + .saturating_add(Weight::from_parts(76_505, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, 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 `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `380 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_440_000 picoseconds. - Weight::from_parts(34_652_647, 0) + // Minimum execution time: 31_269_000 picoseconds. + Weight::from_parts(30_661_898, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 517 - .saturating_add(Weight::from_parts(41_942, 0).saturating_mul(l.into())) - // Standard Error: 920 - .saturating_add(Weight::from_parts(66_074, 0).saturating_mul(s.into())) + // Standard Error: 1_394 + .saturating_add(Weight::from_parts(39_300, 0).saturating_mul(l.into())) + // Standard Error: 2_480 + .saturating_add(Weight::from_parts(78_849, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, 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 `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `380 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_880_000 picoseconds. - Weight::from_parts(39_625_819, 0) + // Minimum execution time: 33_040_000 picoseconds. + Weight::from_parts(32_469_674, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_032 - .saturating_add(Weight::from_parts(29_856, 0).saturating_mul(l.into())) - // Standard Error: 1_837 - .saturating_add(Weight::from_parts(6_210, 0).saturating_mul(s.into())) + // Standard Error: 1_418 + .saturating_add(Weight::from_parts(44_206, 0).saturating_mul(l.into())) + // Standard Error: 2_523 + .saturating_add(Weight::from_parts(74_224, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `451 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 68_294_000 picoseconds. - Weight::from_parts(68_313_394, 0) + // Minimum execution time: 62_032_000 picoseconds. + Weight::from_parts(63_305_621, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 983 - .saturating_add(Weight::from_parts(48_156, 0).saturating_mul(l.into())) - // Standard Error: 1_750 - .saturating_add(Weight::from_parts(87_719, 0).saturating_mul(s.into())) + // Standard Error: 2_277 + .saturating_add(Weight::from_parts(42_767, 0).saturating_mul(l.into())) + // Standard Error: 4_051 + .saturating_add(Weight::from_parts(65_487, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `554 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 70_529_000 picoseconds. - Weight::from_parts(70_619_962, 0) + // Minimum execution time: 63_303_000 picoseconds. + Weight::from_parts(65_180_847, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 1_259 - .saturating_add(Weight::from_parts(50_685, 0).saturating_mul(l.into())) - // Standard Error: 2_241 - .saturating_add(Weight::from_parts(91_444, 0).saturating_mul(s.into())) + // Standard Error: 2_220 + .saturating_add(Weight::from_parts(28_829, 0).saturating_mul(l.into())) + // Standard Error: 3_951 + .saturating_add(Weight::from_parts(84_970, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -192,59 +195,70 @@ impl pallet_vesting::WeightInfo for WeightInfo { /// 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) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, 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 force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `555 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 41_497_000 picoseconds. - Weight::from_parts(38_763_834, 4764) - // Standard Error: 2_030 - .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) - // Standard Error: 3_750 - .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `378 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_428_000 picoseconds. - Weight::from_parts(35_604_430, 0) + // Minimum execution time: 31_440_000 picoseconds. + Weight::from_parts(30_773_053, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 504 - .saturating_add(Weight::from_parts(43_191, 0).saturating_mul(l.into())) - // Standard Error: 931 - .saturating_add(Weight::from_parts(66_795, 0).saturating_mul(s.into())) + // Standard Error: 1_474 + .saturating_add(Weight::from_parts(43_019, 0).saturating_mul(l.into())) + // Standard Error: 2_723 + .saturating_add(Weight::from_parts(73_360, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, 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: `378 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 40_696_000 picoseconds. - Weight::from_parts(39_741_284, 0) + // Minimum execution time: 34_221_000 picoseconds. + Weight::from_parts(33_201_125, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 1_751 + .saturating_add(Weight::from_parts(44_088, 0).saturating_mul(l.into())) + // Standard Error: 3_234 + .saturating_add(Weight::from_parts(86_228, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, 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 force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `451 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `4764` + // Minimum execution time: 35_553_000 picoseconds. + Weight::from_parts(34_974_083, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 478 - .saturating_add(Weight::from_parts(43_792, 0).saturating_mul(l.into())) - // Standard Error: 883 - .saturating_add(Weight::from_parts(66_540, 0).saturating_mul(s.into())) + // Standard Error: 1_560 + .saturating_add(Weight::from_parts(34_615, 0).saturating_mul(l.into())) + // Standard Error: 2_882 + .saturating_add(Weight::from_parts(83_419, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs index 7c307deec4c6..ec67268d1449 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_whitelist` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-aahe6cbd-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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_whitelist // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_whitelist -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,67 +52,75 @@ pub struct WeightInfo(PhantomData); impl pallet_whitelist::WeightInfo for WeightInfo { /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `223` // Estimated: `3556` - // Minimum execution time: 20_035_000 picoseconds. - Weight::from_parts(20_452_000, 0) + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_042_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// 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) + /// 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: `352` // Estimated: `3556` - // Minimum execution time: 20_247_000 picoseconds. - Weight::from_parts(20_808_000, 0) + // Minimum execution time: 18_250_000 picoseconds. + Weight::from_parts(19_026_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:1 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `428 + n * (1 ±0)` // Estimated: `3892 + n * (1 ±0)` - // Minimum execution time: 32_633_000 picoseconds. - Weight::from_parts(32_855_000, 0) + // Minimum execution time: 28_741_000 picoseconds. + Weight::from_parts(29_024_000, 0) .saturating_add(Weight::from_parts(0, 3892)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_305, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// 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) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `3556` - // Minimum execution time: 23_833_000 picoseconds. - Weight::from_parts(24_698_994, 0) + // Minimum execution time: 21_670_000 picoseconds. + Weight::from_parts(22_561_364, 0) .saturating_add(Weight::from_parts(0, 3556)) // Standard Error: 4 - .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 5544ca44658c..d5cf33515e6b 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,23 +17,25 @@ //! 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-02-29, 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` //! 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_xcm // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -60,8 +62,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 25_043_000 picoseconds. - Weight::from_parts(25_682_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(2)) @@ -80,8 +82,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 107_570_000 picoseconds. - Weight::from_parts(109_878_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(3)) @@ -100,8 +102,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `232` // Estimated: `3697` - // Minimum execution time: 106_341_000 picoseconds. - Weight::from_parts(109_135_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(3)) @@ -120,8 +122,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 108_372_000 picoseconds. - Weight::from_parts(112_890_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(3)) @@ -130,8 +132,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_957_000 picoseconds. - Weight::from_parts(7_417_000, 0) + // Minimum execution time: 6_979_000 picoseconds. + Weight::from_parts(7_342_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) @@ -140,8 +142,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_053_000 picoseconds. - Weight::from_parts(7_462_000, 0) + // Minimum execution time: 7_144_000 picoseconds. + Weight::from_parts(7_297_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,8 +151,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_037_000, 0) + // Minimum execution time: 1_886_000 picoseconds. + Weight::from_parts(1_995_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -171,8 +173,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 30_417_000 picoseconds. - Weight::from_parts(31_191_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(5)) @@ -193,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `360` // Estimated: `3825` - // Minimum execution time: 36_666_000 picoseconds. - Weight::from_parts(37_779_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(4)) @@ -205,8 +207,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 1_884_000 picoseconds. + Weight::from_parts(2_028_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -216,8 +218,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_188_000 picoseconds. - Weight::from_parts(16_435_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(2)) @@ -228,8 +230,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_431_000 picoseconds. - Weight::from_parts(16_935_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(2)) @@ -240,8 +242,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 18_460_000 picoseconds. - Weight::from_parts(18_885_000, 0) + // 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)) } @@ -259,8 +261,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `6156` - // Minimum execution time: 29_623_000 picoseconds. - Weight::from_parts(30_661_000, 0) + // Minimum execution time: 30_373_000 picoseconds. + Weight::from_parts(30_972_000, 0) .saturating_add(Weight::from_parts(0, 6156)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -271,8 +273,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 12_043_000 picoseconds. - Weight::from_parts(12_360_000, 0) + // 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)) } @@ -282,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 16_511_000 picoseconds. - Weight::from_parts(17_011_000, 0) + // 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)) .saturating_add(T::DbWeight::get().writes(2)) @@ -302,8 +304,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `13581` - // Minimum execution time: 39_041_000 picoseconds. - Weight::from_parts(39_883_000, 0) + // 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)) @@ -316,8 +318,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_030_000 picoseconds. - Weight::from_parts(2_150_000, 0) + // Minimum execution time: 2_145_000 picoseconds. + Weight::from_parts(2_255_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -328,8 +330,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_615_000 picoseconds. - Weight::from_parts(23_008_000, 0) + // Minimum execution time: 22_518_000 picoseconds. + Weight::from_parts(22_926_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs new file mode 100644 index 000000000000..dc5e5d8ca4b1 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs @@ -0,0 +1,191 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_xcm_benchmarks::fungible` +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_xcm_benchmarks::fungible +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_xcm_benchmarks::fungible`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_benchmarks::fungible::WeightInfo for WeightInfo { + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn withdraw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 27_223_000 picoseconds. + Weight::from_parts(27_947_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn transfer_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `6196` + // Minimum execution time: 36_502_000 picoseconds. + Weight::from_parts(37_023_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(2)) + .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: `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`) + fn transfer_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `6196` + // Minimum execution time: 85_152_000 picoseconds. + Weight::from_parts(86_442_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(6)) + .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`) + fn reserve_asset_deposited() -> 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)) + } + /// 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`) + fn initiate_reserve_withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 56_571_000 picoseconds. + Weight::from_parts(58_163_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .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`) + fn receive_teleported_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 27_411_000 picoseconds. + Weight::from_parts(27_953_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .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`) + fn deposit_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 20_776_000 picoseconds. + Weight::from_parts(21_145_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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`) + fn deposit_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 51_738_000 picoseconds. + Weight::from_parts(53_251_000, 0) + .saturating_add(Weight::from_parts(0, 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`) + fn initiate_teleport() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 39_333_000 picoseconds. + Weight::from_parts(40_515_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs new file mode 100644 index 000000000000..1595a6dfbe4b --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs @@ -0,0 +1,354 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_xcm_benchmarks::generic` +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_xcm_benchmarks::generic +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_xcm_benchmarks::generic`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_benchmarks::generic::WeightInfo for WeightInfo { + /// 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`) + fn report_holding() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 55_210_000 picoseconds. + Weight::from_parts(56_613_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn buy_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_246_000 picoseconds. + Weight::from_parts(1_339_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `XcmPallet::Queries` (r:1 w:0) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn query_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3465` + // Minimum execution time: 5_377_000 picoseconds. + Weight::from_parts(5_549_000, 0) + .saturating_add(Weight::from_parts(0, 3465)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn transact() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_008_000 picoseconds. + Weight::from_parts(7_361_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn refund_surplus() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(1_848_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_error_handler() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_198_000 picoseconds. + Weight::from_parts(1_265_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_appendix() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_267_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn clear_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_193_000 picoseconds. + Weight::from_parts(1_258_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn descend_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_268_000 picoseconds. + Weight::from_parts(1_342_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn clear_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_173_000 picoseconds. + Weight::from_parts(1_248_000, 0) + .saturating_add(Weight::from_parts(0, 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: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`) + fn report_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 53_715_000 picoseconds. + Weight::from_parts(54_860_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) + /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `23` + // Estimated: `3488` + // Minimum execution time: 8_621_000 picoseconds. + Weight::from_parts(8_903_000, 0) + .saturating_add(Weight::from_parts(0, 3488)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn trap() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_211_000 picoseconds. + Weight::from_parts(1_281_000, 0) + .saturating_add(Weight::from_parts(0, 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`) + fn subscribe_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 26_448_000 picoseconds. + Weight::from_parts(27_057_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn unsubscribe_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_498_000 picoseconds. + Weight::from_parts(3_614_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn burn_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_575_000 picoseconds. + Weight::from_parts(1_698_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_334_000 picoseconds. + Weight::from_parts(1_435_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_244_000 picoseconds. + Weight::from_parts(1_337_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_244_000 picoseconds. + Weight::from_parts(1_331_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_407_000 picoseconds. + Weight::from_parts(1_522_000, 0) + .saturating_add(Weight::from_parts(0, 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: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`) + fn query_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 62_963_000 picoseconds. + Weight::from_parts(64_556_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn expect_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_458_000 picoseconds. + Weight::from_parts(8_741_000, 0) + .saturating_add(Weight::from_parts(0, 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: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`) + fn report_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 54_068_000 picoseconds. + Weight::from_parts(55_665_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn clear_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_290_000 picoseconds. + Weight::from_parts(1_348_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_189_000 picoseconds. + Weight::from_parts(1_268_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn clear_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_276_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_fees_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_253_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn unpaid_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_250_000 picoseconds. + 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/polkadot_runtime_common_assigned_slots.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_assigned_slots.rs index 2aaf282c59d5..fd13c2ac9461 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_assigned_slots.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_assigned_slots.rs @@ -16,26 +16,28 @@ //! Autogenerated weights for `runtime_common::assigned_slots` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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=runtime_common::assigned_slots // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_common::assigned_slots -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,15 +70,15 @@ impl polkadot_runtime_common::assigned_slots::WeightInf /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn assign_perm_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `673` - // Estimated: `4138` - // Minimum execution time: 84_646_000 picoseconds. - Weight::from_parts(91_791_000, 0) - .saturating_add(Weight::from_parts(0, 4138)) + // Measured: `730` + // Estimated: `4195` + // Minimum execution time: 71_337_000 picoseconds. + Weight::from_parts(80_807_000, 0) + .saturating_add(Weight::from_parts(0, 4195)) .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Registrar::Paras` (r:1 w:1) + /// Storage: `Registrar::Paras` (r:1 w:0) /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:1) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -98,13 +100,13 @@ impl polkadot_runtime_common::assigned_slots::WeightInf /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn assign_temp_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `673` - // Estimated: `4138` - // Minimum execution time: 68_091_000 picoseconds. - Weight::from_parts(77_310_000, 0) - .saturating_add(Weight::from_parts(0, 4138)) + // Measured: `730` + // Estimated: `4195` + // Minimum execution time: 60_188_000 picoseconds. + Weight::from_parts(63_932_000, 0) + .saturating_add(Weight::from_parts(0, 4195)) .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) @@ -118,11 +120,11 @@ impl polkadot_runtime_common::assigned_slots::WeightInf /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unassign_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `823` - // Estimated: `4288` - // Minimum execution time: 38_081_000 picoseconds. - Weight::from_parts(40_987_000, 0) - .saturating_add(Weight::from_parts(0, 4288)) + // Measured: `856` + // Estimated: `4321` + // Minimum execution time: 35_764_000 picoseconds. + Weight::from_parts(38_355_000, 0) + .saturating_add(Weight::from_parts(0, 4321)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -132,8 +134,8 @@ impl polkadot_runtime_common::assigned_slots::WeightInf // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_182_000 picoseconds. - Weight::from_parts(7_437_000, 0) + // Minimum execution time: 4_634_000 picoseconds. + Weight::from_parts(4_852_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -143,8 +145,8 @@ impl polkadot_runtime_common::assigned_slots::WeightInf // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_153_000 picoseconds. - Weight::from_parts(7_456_000, 0) + // Minimum execution time: 4_563_000 picoseconds. + Weight::from_parts(4_829_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs index 897dc1c1752a..acf2da8cab96 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::auctions` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::auctions // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_auctions.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,84 +58,82 @@ impl polkadot_runtime_common::auctions::WeightInfo for // Proof Size summary in bytes: // Measured: `4` // Estimated: `1493` - // Minimum execution time: 12_805_000 picoseconds. - Weight::from_parts(13_153_000, 0) + // Minimum execution time: 7_307_000 picoseconds. + Weight::from_parts(7_680_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:2 w:2) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:0) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionInfo` (r:1 w:0) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:1 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::Winning` (r:1 w:1) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::ReservedAmounts` (r:2 w:2) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn bid() -> Weight { // Proof Size summary in bytes: - // Measured: `728` + // Measured: `761` // Estimated: `6060` - // Minimum execution time: 77_380_000 picoseconds. - Weight::from_parts(80_503_000, 0) + // Minimum execution time: 75_448_000 picoseconds. + Weight::from_parts(78_716_000, 0) .saturating_add(Weight::from_parts(0, 6060)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe NextRandomness (r:1 w:0) - /// Proof: Babe NextRandomness (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: Babe EpochStart (r:1 w:0) - /// Proof: Babe EpochStart (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:2 w:2) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: `Auctions::AuctionInfo` (r:1 w:1) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Babe::NextRandomness` (r:1 w:0) + /// Proof: `Babe::NextRandomness` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Babe::EpochStart` (r:1 w:0) + /// Proof: `Babe::EpochStart` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:0) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Auctions::Winning` (r:3600 w:3600) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::ReservedAmounts` (r:37 w:36) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:36 w:36) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:2 w:2) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn on_initialize() -> Weight { // Proof Size summary in bytes: - // Measured: `6947789` + // Measured: `6947017` // Estimated: `15822990` - // Minimum execution time: 6_311_055_000 picoseconds. - Weight::from_parts(6_409_142_000, 0) + // Minimum execution time: 7_120_207_000 picoseconds. + Weight::from_parts(7_273_496_000, 0) .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3683)) - .saturating_add(T::DbWeight::get().writes(3678)) + .saturating_add(T::DbWeight::get().reads(3682)) + .saturating_add(T::DbWeight::get().writes(3677)) } - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:0 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Auctions::ReservedAmounts` (r:37 w:36) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:36 w:36) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Auctions::Winning` (r:3600 w:3600) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionInfo` (r:0 w:1) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn cancel_auction() -> Weight { // Proof Size summary in bytes: // Measured: `177732` // Estimated: `15822990` - // Minimum execution time: 4_849_561_000 picoseconds. - Weight::from_parts(4_955_226_000, 0) + // Minimum execution time: 5_536_281_000 picoseconds. + Weight::from_parts(5_675_163_000, 0) .saturating_add(Weight::from_parts(0, 15822990)) .saturating_add(T::DbWeight::get().reads(3673)) .saturating_add(T::DbWeight::get().writes(3673)) diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs index 8fbc798dbd46..3871310678ef 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::claims` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::claims // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_claims.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_claims.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -67,100 +70,113 @@ impl polkadot_runtime_common::claims::WeightInfo for We // Proof Size summary in bytes: // Measured: `558` // Estimated: `4764` - // Minimum execution time: 144_931_000 picoseconds. - Weight::from_parts(156_550_000, 0) + // Minimum execution time: 181_028_000 picoseconds. + Weight::from_parts(194_590_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:0 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:0 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:0 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) + /// Storage: `Claims::Total` (r:1 w:1) + /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:0 w:1) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Claims` (r:0 w:1) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:0 w:1) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) fn mint_claim() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `1701` - // Minimum execution time: 11_300_000 picoseconds. - Weight::from_parts(11_642_000, 0) + // Minimum execution time: 11_224_000 picoseconds. + Weight::from_parts(13_342_000, 0) .saturating_add(Weight::from_parts(0, 1701)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Claims::Claims` (r:1 w:1) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:1) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Total` (r:1 w:1) + /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:1 w:1) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) fn claim_attest() -> Weight { // Proof Size summary in bytes: // Measured: `558` // Estimated: `4764` - // Minimum execution time: 149_112_000 picoseconds. - Weight::from_parts(153_872_000, 0) + // Minimum execution time: 187_964_000 picoseconds. + Weight::from_parts(202_553_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Claims::Preclaims` (r:1 w:1) + /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:1) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Claims` (r:1 w:1) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Total` (r:1 w:1) + /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:1 w:1) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, 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) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) fn attest() -> Weight { // Proof Size summary in bytes: // Measured: `632` // Estimated: `4764` - // Minimum execution time: 69_619_000 picoseconds. - Weight::from_parts(79_242_000, 0) + // Minimum execution time: 78_210_000 picoseconds. + Weight::from_parts(84_581_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: Claims Claims (r:1 w:2) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:2) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:2) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) + /// Storage: `Claims::Claims` (r:1 w:2) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:1 w:2) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:2) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Preclaims` (r:1 w:1) + /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) fn move_claim() -> Weight { // Proof Size summary in bytes: // Measured: `440` // Estimated: `3905` - // Minimum execution time: 22_066_000 picoseconds. - Weight::from_parts(22_483_000, 0) + // Minimum execution time: 33_940_000 picoseconds. + Weight::from_parts(48_438_000, 0) .saturating_add(Weight::from_parts(0, 3905)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(7)) } + /// Storage: `Claims::Preclaims` (r:1 w:0) + /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:0) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn prevalidate_attests() -> Weight { + // Proof Size summary in bytes: + // Measured: `296` + // Estimated: `3761` + // Minimum execution time: 9_025_000 picoseconds. + Weight::from_parts(10_563_000, 0) + .saturating_add(Weight::from_parts(0, 3761)) + .saturating_add(T::DbWeight::get().reads(2)) + } } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs index b75ff8d42e7e..2a01de67acc5 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::crowdloan` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::crowdloan // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_crowdloan.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,158 +64,154 @@ impl polkadot_runtime_common::crowdloan::WeightInfo for // Proof Size summary in bytes: // Measured: `438` // Estimated: `3903` - // Minimum execution time: 50_399_000 picoseconds. - Weight::from_parts(51_641_000, 0) + // Minimum execution time: 46_095_000 picoseconds. + Weight::from_parts(48_111_000, 0) .saturating_add(Weight::from_parts(0, 3903)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:0) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:1 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::AuctionInfo` (r:1 w:0) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Crowdloan::EndingsCount` (r:1 w:0) + /// Proof: `Crowdloan::EndingsCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NewRaise` (r:1 w:1) + /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) fn contribute() -> Weight { // Proof Size summary in bytes: - // Measured: `530` - // Estimated: `3995` - // Minimum execution time: 128_898_000 picoseconds. - Weight::from_parts(130_277_000, 0) - .saturating_add(Weight::from_parts(0, 3995)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) + // Measured: `563` + // Estimated: `4028` + // Minimum execution time: 133_059_000 picoseconds. + Weight::from_parts(136_515_000, 0) + .saturating_add(Weight::from_parts(0, 4028)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (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: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - /// Proof Skipped: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`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: UNKNOWN KEY `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) fn withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `689` + // Measured: `687` // Estimated: `6196` - // Minimum execution time: 69_543_000 picoseconds. - Weight::from_parts(71_522_000, 0) + // Minimum execution time: 71_733_000 picoseconds. + Weight::from_parts(74_034_000, 0) .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `k` is `[0, 1000]`. fn refund(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `127 + k * (189 ±0)` - // Estimated: `140 + k * (189 ±0)` - // Minimum execution time: 50_735_000 picoseconds. - Weight::from_parts(52_282_000, 0) - .saturating_add(Weight::from_parts(0, 140)) - // Standard Error: 21_607 - .saturating_add(Weight::from_parts(38_955_985, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `125 + k * (189 ±0)` + // Estimated: `138 + k * (189 ±0)` + // Minimum execution time: 46_016_000 picoseconds. + Weight::from_parts(48_260_000, 0) + .saturating_add(Weight::from_parts(0, 138)) + // Standard Error: 21_140 + .saturating_add(Weight::from_parts(39_141_925, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 189).saturating_mul(k.into())) } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (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: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`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`) fn dissolve() -> Weight { // Proof Size summary in bytes: - // Measured: `515` + // Measured: `514` // Estimated: `6196` - // Minimum execution time: 43_100_000 picoseconds. - Weight::from_parts(44_272_000, 0) + // Minimum execution time: 44_724_000 picoseconds. + Weight::from_parts(47_931_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) fn edit() -> Weight { // Proof Size summary in bytes: - // Measured: `235` - // Estimated: `3700` - // Minimum execution time: 18_702_000 picoseconds. - Weight::from_parts(19_408_000, 0) - .saturating_add(Weight::from_parts(0, 3700)) + // Measured: `234` + // Estimated: `3699` + // Minimum execution time: 19_512_000 picoseconds. + Weight::from_parts(21_129_000, 0) + .saturating_add(Weight::from_parts(0, 3699)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Storage: `Crowdloan::Funds` (r:1 w:0) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) fn add_memo() -> Weight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 25_568_000 picoseconds. - Weight::from_parts(26_203_000, 0) + // Minimum execution time: 33_529_000 picoseconds. + Weight::from_parts(37_082_000, 0) .saturating_add(Weight::from_parts(0, 3877)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `Crowdloan::Funds` (r:1 w:0) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NewRaise` (r:1 w:1) + /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn poke() -> Weight { // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `3704` - // Minimum execution time: 17_832_000 picoseconds. - Weight::from_parts(18_769_000, 0) - .saturating_add(Weight::from_parts(0, 3704)) + // Measured: `238` + // Estimated: `3703` + // Minimum execution time: 23_153_000 picoseconds. + Weight::from_parts(24_181_000, 0) + .saturating_add(Weight::from_parts(0, 3703)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:1) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:100 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Paras ParaLifecycles (r:100 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:100 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:100 w:100) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:100 w:100) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Auctions::AuctionInfo` (r:1 w:0) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Crowdloan::EndingsCount` (r:1 w:1) + /// Proof: `Crowdloan::EndingsCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NewRaise` (r:1 w:1) + /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::Funds` (r:100 w:0) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:0) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Paras::ParaLifecycles` (r:100 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:100 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::Winning` (r:1 w:1) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::ReservedAmounts` (r:100 w:100) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:100 w:100) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[2, 100]`. fn on_initialize(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `197 + n * (356 ±0)` + // Measured: `229 + n * (356 ±0)` // Estimated: `5385 + n * (2832 ±0)` - // Minimum execution time: 128_319_000 picoseconds. - Weight::from_parts(130_877_000, 0) + // Minimum execution time: 120_164_000 picoseconds. + Weight::from_parts(3_390_119, 0) .saturating_add(Weight::from_parts(0, 5385)) - // Standard Error: 61_381 - .saturating_add(Weight::from_parts(60_209_202, 0).saturating_mul(n.into())) + // Standard Error: 41_727 + .saturating_add(Weight::from_parts(54_453_016, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs index 4ea6f6796801..3df3c6c8dd92 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs @@ -1,36 +1,43 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Polkadot. -// 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. +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . //! Autogenerated weights for `runtime_common::identity_migrator` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-07, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `sbtb`, CPU: `13th Gen Intel(R) Core(TM) i7-1365U` +//! HOSTNAME: `runner-bn-ce5rx-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/release/polkadot +// ./target/production/polkadot // benchmark // pallet // --chain=rococo-dev -// --steps=2 -// --repeat=1 +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::identity_migrator // --extrinsic=* -// --output=./migrator-release.rs +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -44,7 +51,7 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl polkadot_runtime_common::identity_migrator::WeightInfo for WeightInfo { /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) @@ -63,34 +70,34 @@ impl polkadot_runtime_common::identity_migrator::Weight /// The range of component `s` is `[0, 100]`. fn reap_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7292 + r * (8 ±0) + s * (32 ±0)` - // Estimated: `11003 + r * (8 ±0) + s * (33 ±0)` - // Minimum execution time: 163_756_000 picoseconds. - Weight::from_parts(158_982_500, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_143_629 - .saturating_add(Weight::from_parts(238_675, 0).saturating_mul(r.into())) - // Standard Error: 228_725 - .saturating_add(Weight::from_parts(1_529_645, 0).saturating_mul(s.into())) + // Measured: `7457 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037 + r * (7 ±0) + s * (32 ±0)` + // Minimum execution time: 157_343_000 picoseconds. + Weight::from_parts(159_289_236, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 16_439 + .saturating_add(Weight::from_parts(224_293, 0).saturating_mul(r.into())) + // Standard Error: 3_367 + .saturating_add(Weight::from_parts(1_383_637, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(6)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, 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::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `7229` - // Estimated: `11003` - // Minimum execution time: 137_570_000 picoseconds. - Weight::from_parts(137_570_000, 0) - .saturating_add(Weight::from_parts(0, 11003)) + // Measured: `7242` + // Estimated: `11037` + // Minimum execution time: 114_384_000 picoseconds. + Weight::from_parts(115_741_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs index 0ce09d1be2a4..ad261a7f7747 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::paras_registrar` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::paras_registrar // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_paras_registrar.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,167 +58,161 @@ impl polkadot_runtime_common::paras_registrar::WeightIn /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) fn reserve() -> Weight { // Proof Size summary in bytes: - // Measured: `97` - // Estimated: `3562` - // Minimum execution time: 29_948_000 picoseconds. - Weight::from_parts(30_433_000, 0) - .saturating_add(Weight::from_parts(0, 3562)) + // Measured: `96` + // Estimated: `3561` + // Minimum execution time: 24_109_000 picoseconds. + Weight::from_parts(24_922_000, 0) + .saturating_add(Weight::from_parts(0, 3561)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:0 w:1) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpcomingParasGenesis` (r:0 w:1) + /// Proof: `Paras::UpcomingParasGenesis` (`max_values`: None, `max_size`: None, mode: `Measured`) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `616` - // Estimated: `4081` - // Minimum execution time: 6_332_113_000 picoseconds. - Weight::from_parts(6_407_158_000, 0) - .saturating_add(Weight::from_parts(0, 4081)) - .saturating_add(T::DbWeight::get().reads(8)) + // Measured: `352` + // Estimated: `3817` + // Minimum execution time: 7_207_580_000 picoseconds. + Weight::from_parts(7_298_567_000, 0) + .saturating_add(Weight::from_parts(0, 3817)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:0 w:1) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpcomingParasGenesis` (r:0 w:1) + /// Proof: `Paras::UpcomingParasGenesis` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_register() -> Weight { // Proof Size summary in bytes: - // Measured: `533` - // Estimated: `3998` - // Minimum execution time: 6_245_403_000 picoseconds. - Weight::from_parts(6_289_575_000, 0) - .saturating_add(Weight::from_parts(0, 3998)) - .saturating_add(T::DbWeight::get().reads(8)) + // Measured: `269` + // Estimated: `3734` + // Minimum execution time: 7_196_460_000 picoseconds. + Weight::from_parts(7_385_729_000, 0) + .saturating_add(Weight::from_parts(0, 3734)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: Registrar PendingSwap (r:0 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeHash` (r:1 w:0) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Registrar::PendingSwap` (r:0 w:1) + /// Proof: `Registrar::PendingSwap` (`max_values`: None, `max_size`: None, mode: `Measured`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `476` - // Estimated: `3941` - // Minimum execution time: 49_822_000 picoseconds. - Weight::from_parts(50_604_000, 0) - .saturating_add(Weight::from_parts(0, 3941)) + // Measured: `499` + // Estimated: `3964` + // Minimum execution time: 54_761_000 picoseconds. + Weight::from_parts(57_931_000, 0) + .saturating_add(Weight::from_parts(0, 3964)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Registrar Paras (r:1 w:0) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:2 w:2) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar PendingSwap (r:1 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:2 w:2) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:2 w:2) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:2 w:2) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::PendingSwap` (r:1 w:1) + /// Proof: `Registrar::PendingSwap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::Funds` (r:2 w:2) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:2 w:2) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) fn swap() -> Weight { // Proof Size summary in bytes: - // Measured: `780` - // Estimated: `6720` - // Minimum execution time: 55_166_000 picoseconds. - Weight::from_parts(56_913_000, 0) - .saturating_add(Weight::from_parts(0, 6720)) + // Measured: `837` + // Estimated: `6777` + // Minimum execution time: 59_564_000 picoseconds. + Weight::from_parts(62_910_000, 0) + .saturating_add(Weight::from_parts(0, 6777)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(8)) } - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 3145728]`. + /// Storage: `Paras::FutureCodeHash` (r:1 w:1) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:1) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) + /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[9, 3145728]`. fn schedule_code_upgrade(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `464` - // Estimated: `3929` - // Minimum execution time: 43_650_000 picoseconds. - Weight::from_parts(43_918_000, 0) - .saturating_add(Weight::from_parts(0, 3929)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(2_041, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `201` + // Estimated: `3666` + // Minimum execution time: 33_106_000 picoseconds. + Weight::from_parts(33_526_000, 0) + .saturating_add(Weight::from_parts(0, 3666)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `b` is `[1, 1048576]`. fn set_current_head(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_666_000 picoseconds. - Weight::from_parts(8_893_000, 0) + // Minimum execution time: 5_992_000 picoseconds. + Weight::from_parts(12_059_689, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(855, 0).saturating_mul(b.into())) + // Standard Error: 0 + .saturating_add(Weight::from_parts(959, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs index 8c601aa8486f..b99ee1f9a0d3 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_common::slots` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::slots // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_slots.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_slots.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,80 +56,76 @@ impl polkadot_runtime_common::slots::WeightInfo for Wei /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_lease() -> Weight { // Proof Size summary in bytes: - // Measured: `287` - // Estimated: `3752` - // Minimum execution time: 29_932_000 picoseconds. - Weight::from_parts(30_334_000, 0) - .saturating_add(Weight::from_parts(0, 3752)) + // Measured: `320` + // Estimated: `3785` + // Minimum execution time: 26_570_000 picoseconds. + Weight::from_parts(27_619_000, 0) + .saturating_add(Weight::from_parts(0, 3785)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Slots Leases (r:101 w:100) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:200 w:200) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:100 w:100) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::Parachains` (r:1 w:0) + /// Proof: `Paras::Parachains` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:101 w:100) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:200 w:200) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[0, 100]`. /// The range of component `t` is `[0, 100]`. fn manage_lease_period_start(c: u32, t: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `26 + c * (47 ±0) + t * (308 ±0)` - // Estimated: `2800 + c * (2526 ±0) + t * (2789 ±0)` - // Minimum execution time: 634_547_000 picoseconds. - Weight::from_parts(643_045_000, 0) - .saturating_add(Weight::from_parts(0, 2800)) - // Standard Error: 81_521 - .saturating_add(Weight::from_parts(2_705_219, 0).saturating_mul(c.into())) - // Standard Error: 81_521 - .saturating_add(Weight::from_parts(11_464_132, 0).saturating_mul(t.into())) + // Measured: `594 + c * (20 ±0) + t * (234 ±0)` + // Estimated: `4065 + c * (2496 ±0) + t * (2709 ±0)` + // Minimum execution time: 729_793_000 picoseconds. + Weight::from_parts(740_820_000, 0) + .saturating_add(Weight::from_parts(0, 4065)) + // Standard Error: 88_206 + .saturating_add(Weight::from_parts(2_793_142, 0).saturating_mul(c.into())) + // Standard Error: 88_206 + .saturating_add(Weight::from_parts(8_933_065, 0).saturating_mul(t.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2526).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 2789).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 2496).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2709).saturating_mul(t.into())) } - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:8 w:8) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:8 w:8) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn clear_all_leases() -> Weight { // Proof Size summary in bytes: - // Measured: `2759` + // Measured: `2792` // Estimated: `21814` - // Minimum execution time: 129_756_000 picoseconds. - Weight::from_parts(131_810_000, 0) + // Minimum execution time: 123_888_000 picoseconds. + Weight::from_parts(131_245_000, 0) .saturating_add(Weight::from_parts(0, 21814)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(9)) } - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: `Slots::Leases` (r:1 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn trigger_onboard() -> Weight { // Proof Size summary in bytes: - // Measured: `707` - // Estimated: `4172` - // Minimum execution time: 29_527_000 picoseconds. - Weight::from_parts(30_055_000, 0) - .saturating_add(Weight::from_parts(0, 4172)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `612` + // Estimated: `4077` + // Minimum execution time: 27_341_000 picoseconds. + Weight::from_parts(28_697_000, 0) + .saturating_add(Weight::from_parts(0, 4077)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) } } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs index 5592a85c90fa..3ca49aaa1651 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-29, 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` //! 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=runtime_parachains::configuration // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_parachains::configuration -// --chain=rococo-dev // --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,8 +60,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_789_000 picoseconds. - Weight::from_parts(8_269_000, 0) + // Minimum execution time: 7_689_000 picoseconds. + Weight::from_parts(8_089_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -74,8 +76,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_851_000 picoseconds. - Weight::from_parts(8_152_000, 0) + // Minimum execution time: 7_735_000 picoseconds. + Weight::from_parts(8_150_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -90,8 +92,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_960_000 picoseconds. - Weight::from_parts(8_276_000, 0) + // Minimum execution time: 7_902_000 picoseconds. + Weight::from_parts(8_196_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -116,8 +118,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_912_000 picoseconds. - Weight::from_parts(8_164_000, 0) + // Minimum execution time: 7_634_000 picoseconds. + Weight::from_parts(7_983_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -132,8 +134,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 9_782_000 picoseconds. - Weight::from_parts(10_373_000, 0) + // Minimum execution time: 9_580_000 picoseconds. + Weight::from_parts(9_989_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -148,8 +150,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_870_000 picoseconds. - Weight::from_parts(8_274_000, 0) + // Minimum execution time: 7_787_000 picoseconds. + Weight::from_parts(8_008_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -164,8 +166,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 9_960_000 picoseconds. - Weight::from_parts(10_514_000, 0) + // Minimum execution time: 9_557_000 picoseconds. + Weight::from_parts(9_994_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -180,8 +182,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_913_000 picoseconds. - Weight::from_parts(8_338_000, 0) + // Minimum execution time: 7_775_000 picoseconds. + Weight::from_parts(7_989_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs index a20515502b19..6f86d6a12599 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::disputes` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_parachains::disputes // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_disputes.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,8 +56,8 @@ impl polkadot_runtime_parachains::disputes::WeightInfo // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_937_000 picoseconds. - Weight::from_parts(3_082_000, 0) + // Minimum execution time: 1_855_000 picoseconds. + Weight::from_parts(2_015_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs index 6065c32b1741..b915c4ec0f36 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::initializer` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_parachains::initializer // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_initializer.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,11 +57,11 @@ impl polkadot_runtime_parachains::initializer::WeightIn // Proof Size summary in bytes: // Measured: `0 + d * (11 ±0)` // Estimated: `1480 + d * (11 ±0)` - // Minimum execution time: 3_771_000 picoseconds. - Weight::from_parts(6_491_437, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_728_000, 0) .saturating_add(Weight::from_parts(0, 1480)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_356, 0).saturating_mul(d.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(2_499, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 11).saturating_mul(d.into())) diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_on_demand.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_on_demand.rs index 0c36eeaf7d45..1dd62d129f9a 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_on_demand.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_on_demand.rs @@ -23,12 +23,18 @@ //! 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=runtime_parachains::assigner_on_demand // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras.rs index 2dcabb7c36bb..c463552b6ad4 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::paras` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, 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-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_parachains::paras // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_paras.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,230 +67,231 @@ impl polkadot_runtime_parachains::paras::WeightInfo for // Proof Size summary in bytes: // Measured: `8309` // Estimated: `11774` - // Minimum execution time: 31_941_000 picoseconds. - Weight::from_parts(32_139_000, 0) + // Minimum execution time: 27_488_000 picoseconds. + Weight::from_parts(27_810_000, 0) .saturating_add(Weight::from_parts(0, 11774)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_011, 0).saturating_mul(c.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(2_189, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 1048576]`. fn force_set_current_head(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_275_000 picoseconds. - Weight::from_parts(8_321_000, 0) + // Minimum execution time: 5_793_000 picoseconds. + Weight::from_parts(7_987_606, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(971, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().writes(1)) } - // Storage: Paras Heads (r:0 w:1) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_set_most_recent_context() -> Weight { - Weight::from_parts(10_155_000, 0) - // Standard Error: 0 - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_733_000 picoseconds. + Weight::from_parts(2_954_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::FutureCodeHash` (r:1 w:1) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) + /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[1, 3145728]`. fn force_schedule_code_upgrade(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8715` - // Estimated: `12180` - // Minimum execution time: 49_923_000 picoseconds. - Weight::from_parts(50_688_000, 0) - .saturating_add(Weight::from_parts(0, 12180)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_976, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `8452` + // Estimated: `11917` + // Minimum execution time: 6_072_000 picoseconds. + Weight::from_parts(6_128_000, 0) + .saturating_add(Weight::from_parts(0, 11917)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `s` is `[1, 1048576]`. fn force_note_new_head(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `3560` - // Minimum execution time: 14_408_000 picoseconds. - Weight::from_parts(14_647_000, 0) - .saturating_add(Weight::from_parts(0, 3560)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `163` + // Estimated: `3628` + // Minimum execution time: 15_166_000 picoseconds. + Weight::from_parts(21_398_053, 0) + .saturating_add(Weight::from_parts(0, 3628)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(976, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_queue_action() -> Weight { // Proof Size summary in bytes: - // Measured: `4288` - // Estimated: `7753` - // Minimum execution time: 20_009_000 picoseconds. - Weight::from_parts(20_518_000, 0) - .saturating_add(Weight::from_parts(0, 7753)) + // Measured: `4312` + // Estimated: `7777` + // Minimum execution time: 16_345_000 picoseconds. + Weight::from_parts(16_712_000, 0) + .saturating_add(Weight::from_parts(0, 7777)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `c` is `[1, 3145728]`. fn add_trusted_validation_code(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `946` - // Estimated: `4411` - // Minimum execution time: 80_626_000 picoseconds. - Weight::from_parts(52_721_755, 0) - .saturating_add(Weight::from_parts(0, 4411)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `683` + // Estimated: `4148` + // Minimum execution time: 78_076_000 picoseconds. + Weight::from_parts(123_193_814, 0) + .saturating_add(Weight::from_parts(0, 4148)) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_770, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Paras CodeByHashRefs (r:1 w:0) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:0) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:0 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn poke_unused_validation_code() -> Weight { // Proof Size summary in bytes: // Measured: `28` // Estimated: `3493` - // Minimum execution time: 6_692_000 picoseconds. - Weight::from_parts(7_009_000, 0) + // Minimum execution time: 5_184_000 picoseconds. + Weight::from_parts(5_430_000, 0) .saturating_add(Weight::from_parts(0, 3493)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) fn include_pvf_check_statement() -> Weight { // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 87_994_000 picoseconds. - Weight::from_parts(89_933_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) + // Measured: `26706` + // Estimated: `30171` + // Minimum execution time: 102_995_000 picoseconds. + Weight::from_parts(108_977_000, 0) + .saturating_add(Weight::from_parts(0, 30171)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras UpcomingUpgrades (r:1 w:1) - /// Proof Skipped: Paras UpcomingUpgrades (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras FutureCodeUpgrades (r:0 w:100) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpcomingUpgrades` (r:1 w:1) + /// Proof: `Paras::UpcomingUpgrades` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:0 w:100) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight { // Proof Size summary in bytes: - // Measured: `27523` - // Estimated: `30988` - // Minimum execution time: 783_222_000 picoseconds. - Weight::from_parts(794_959_000, 0) - .saturating_add(Weight::from_parts(0, 30988)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `27360` + // Estimated: `30825` + // Minimum execution time: 709_433_000 picoseconds. + Weight::from_parts(725_074_000, 0) + .saturating_add(Weight::from_parts(0, 30825)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(104)) } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight { // Proof Size summary in bytes: - // Measured: `27214` - // Estimated: `30679` - // Minimum execution time: 87_424_000 picoseconds. - Weight::from_parts(88_737_000, 0) - .saturating_add(Weight::from_parts(0, 30679)) + // Measured: `27338` + // Estimated: `30803` + // Minimum execution time: 98_973_000 picoseconds. + Weight::from_parts(104_715_000, 0) + .saturating_add(Weight::from_parts(0, 30803)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight { // Proof Size summary in bytes: - // Measured: `26991` - // Estimated: `30456` - // Minimum execution time: 612_485_000 picoseconds. - Weight::from_parts(621_670_000, 0) - .saturating_add(Weight::from_parts(0, 30456)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `26728` + // Estimated: `30193` + // Minimum execution time: 550_958_000 picoseconds. + Weight::from_parts(564_497_000, 0) + .saturating_add(Weight::from_parts(0, 30193)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight { // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 86_673_000 picoseconds. - Weight::from_parts(87_424_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) + // Measured: `26706` + // Estimated: `30171` + // Minimum execution time: 97_088_000 picoseconds. + Weight::from_parts(103_617_000, 0) + .saturating_add(Weight::from_parts(0, 30171)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs index b7b3d12d4d92..71a0bb6fc7b2 100644 --- a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `polkadot_runtime_parachains::paras_inherent` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-07, 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: @@ -54,10 +54,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -70,23 +72,21 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn enter_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `8967` - // Estimated: `12432` - // Minimum execution time: 144_751_000 picoseconds. - Weight::from_parts(153_966_000, 0) - .saturating_add(Weight::from_parts(0, 12432)) + // Measured: `42760` + // Estimated: `46225` + // Minimum execution time: 228_252_000 picoseconds. + Weight::from_parts(234_368_000, 0) + .saturating_add(Weight::from_parts(0, 46225)) .saturating_add(T::DbWeight::get().reads(15)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -94,10 +94,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -128,16 +130,14 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::Heads` (r:0 w:1) @@ -146,19 +146,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[10, 200]`. + /// The range of component `v` is `[400, 1024]`. fn enter_variable_disputes(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `67786` - // Estimated: `73726 + v * (23 ±0)` - // Minimum execution time: 972_311_000 picoseconds. - Weight::from_parts(645_559_304, 0) - .saturating_add(Weight::from_parts(0, 73726)) - // Standard Error: 53_320 - .saturating_add(Weight::from_parts(41_795_493, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(25)) - .saturating_add(T::DbWeight::get().writes(15)) - .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) + // Measured: `203155` + // Estimated: `209095` + // Minimum execution time: 17_510_015_000 picoseconds. + Weight::from_parts(948_178_084, 0) + .saturating_add(Weight::from_parts(0, 209095)) + // Standard Error: 16_345 + .saturating_add(Weight::from_parts(41_627_958, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(26)) + .saturating_add(T::DbWeight::get().writes(16)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -166,10 +165,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -182,25 +183,21 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn enter_bitfields() -> Weight { // Proof Size summary in bytes: - // Measured: `42374` - // Estimated: `48314` - // Minimum execution time: 361_262_000 picoseconds. - Weight::from_parts(370_617_000, 0) - .saturating_add(Weight::from_parts(0, 48314)) - .saturating_add(T::DbWeight::get().reads(17)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `76066` + // Estimated: `82006` + // Minimum execution time: 501_266_000 picoseconds. + Weight::from_parts(517_989_000, 0) + .saturating_add(Weight::from_parts(0, 82006)) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -208,10 +205,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -236,12 +235,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:0) @@ -252,6 +247,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -262,18 +259,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[101, 200]`. + /// The range of component `v` is `[2, 3]`. fn enter_backed_candidates_variable(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `42830` - // Estimated: `48770` - // Minimum execution time: 1_322_051_000 picoseconds. - Weight::from_parts(1_379_846_608, 0) - .saturating_add(Weight::from_parts(0, 48770)) - // Standard Error: 19_959 - .saturating_add(Weight::from_parts(24_630, 0).saturating_mul(v.into())) + // Measured: `76842` + // Estimated: `82782` + // Minimum execution time: 1_861_799_000 picoseconds. + Weight::from_parts(1_891_155_030, 0) + .saturating_add(Weight::from_parts(0, 82782)) + // Standard Error: 2_415_944 + .saturating_add(Weight::from_parts(7_924_189, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(26)) - .saturating_add(T::DbWeight::get().writes(15)) + .saturating_add(T::DbWeight::get().writes(14)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -281,10 +278,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -309,12 +308,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::FutureCodeHash` (r:1 w:0) @@ -329,6 +324,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -341,12 +338,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_backed_candidate_code_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `42843` - // Estimated: `48783` - // Minimum execution time: 37_550_515_000 picoseconds. - Weight::from_parts(37_886_489_000, 0) - .saturating_add(Weight::from_parts(0, 48783)) + // Measured: `76855` + // Estimated: `82795` + // Minimum execution time: 37_682_370_000 picoseconds. + Weight::from_parts(41_118_445_000, 0) + .saturating_add(Weight::from_parts(0, 82795)) .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(15)) + .saturating_add(T::DbWeight::get().writes(14)) } } diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs b/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs new file mode 100644 index 000000000000..d068f07e7594 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs @@ -0,0 +1,86 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `runtime_common::coretime` +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::coretime +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `runtime_common::coretime`. +pub struct WeightInfo(PhantomData); +impl runtime_common::coretime::WeightInfo for WeightInfo { + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn request_core_count() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_543_000 picoseconds. + Weight::from_parts(7_745_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreSchedules` (r:0 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[1, 100]`. + fn assign_core(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 9_367_000 picoseconds. + Weight::from_parts(9_932_305, 0) + .saturating_add(Weight::from_parts(0, 3645)) + // Standard Error: 231 + .saturating_add(Weight::from_parts(12_947, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/xcm/mod.rs b/polkadot/runtime/rococo/src/weights/xcm/mod.rs index bd2b0fbb8c06..a28b46800874 100644 --- a/polkadot/runtime/rococo/src/weights/xcm/mod.rs +++ b/polkadot/runtime/rococo/src/weights/xcm/mod.rs @@ -24,6 +24,7 @@ use xcm::{latest::prelude::*, DoubleEncoded}; use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; +use xcm::latest::AssetTransferFilter; /// Types of asset supported by the Rococo runtime. pub enum AssetTypes { @@ -110,11 +111,7 @@ impl XcmWeightInfo for RococoXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmBalancesWeight::::transfer_reserve_asset()) } - fn transact( - _origin_kind: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_kind: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -163,12 +160,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 +286,12 @@ impl XcmWeightInfo for RococoXcmWeight { fn unpaid_execution(_: &WeightLimit, _: &Option) -> Weight { XcmGeneric::::unpaid_execution() } + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } + 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..e5915a7986bf 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 set_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 ac379b69e3f2..90a0285cd17b 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -144,6 +144,7 @@ runtime-benchmarks = [ "pallet-staking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 6ba8e6ad3182..69ce187dce40 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -31,11 +31,11 @@ use codec::Encode; use pallet_transaction_payment::FungibleAdapter; use polkadot_runtime_parachains::{ - assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, - configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, disputes as parachains_disputes, - disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, - inclusion as parachains_inclusion, initializer as parachains_initializer, + assigner_coretime as parachains_assigner_coretime, configuration as parachains_configuration, + configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, coretime, + disputes as parachains_disputes, disputes::slashing as parachains_slashing, + dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, + initializer as parachains_initializer, on_demand as parachains_on_demand, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, runtime_api_impl::v11 as runtime_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, @@ -49,8 +49,10 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, derive_impl, genesis_builder_helper::{build_state, get_preset}, + pallet_prelude::Get, parameter_types, traits::{KeyOwnerProofSystem, WithdrawReasons}, + PalletId, }; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_session::historical as session_historical; @@ -78,12 +80,11 @@ 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::{ - BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, OpaqueKeys, - SaturatedConversion, StaticLookup, Verify, + BlakeTwo256, Block as BlockT, ConvertInto, OpaqueKeys, SaturatedConversion, StaticLookup, + Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, @@ -92,6 +93,7 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use xcm::latest::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, XcmHash}; pub use pallet_balances::Call as BalancesCall; #[cfg(feature = "std")] @@ -116,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, @@ -167,14 +169,34 @@ impl frame_system::Config for Runtime { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = UncheckedExtrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } +} + +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: Self::RuntimeCall, extension: Self::Extension) -> Self::Extrinsic { + UncheckedExtrinsic::new_transaction(call, extension) + } +} + parameter_types! { pub storage EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS as u64; pub storage ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; @@ -251,6 +273,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = frame_support::weights::ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = (); } parameter_types! { @@ -372,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! { @@ -395,18 +418,20 @@ impl frame_system::offchain::CreateSignedTransaction for R where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let current_block = System::block_number().saturated_into::().saturating_sub(1); let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -418,16 +443,18 @@ where frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ); - let raw_payload = SignedPayload::new(call, extra) + ) + .into(); + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); + let (call, tx_ext, _) = raw_payload.deconstruct(); let address = Indices::unlookup(account); - Some((call, (address, signature, extra))) + let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext); + Some(transaction) } } @@ -534,7 +561,7 @@ impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type ForceOrigin = frame_system::EnsureRoot; type WeightInfo = (); - type CoretimeOnNewSession = (); + type CoretimeOnNewSession = Coretime; } impl parachains_session_info::Config for Runtime { @@ -552,15 +579,25 @@ impl parachains_paras::Config for Runtime { type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; type OnNewHead = (); - type AssignCoretime = (); + type AssignCoretime = CoretimeAssignmentProvider; } parameter_types! { pub const BrokerId: u32 = 10u32; } +pub struct BrokerPot; +impl Get for BrokerPot { + fn get() -> InteriorLocation { + unimplemented!() + } +} + parameter_types! { pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); + // Keep 2 timeslices worth of revenue information. + pub const MaxHistoricalRevenue: BlockNumber = 2 * 5; + pub const OnDemandPalletId: PalletId = PalletId(*b"py/ondmd"); } impl parachains_dmp::Config for Runtime {} @@ -582,10 +619,47 @@ impl parachains_hrmp::Config for Runtime { type WeightInfo = parachains_hrmp::TestWeightInfo; } -impl parachains_assigner_parachains::Config for Runtime {} +impl parachains_on_demand::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type TrafficDefaultValue = OnDemandTrafficDefaultValue; + type WeightInfo = parachains_on_demand::TestWeightInfo; + type MaxHistoricalRevenue = MaxHistoricalRevenue; + type PalletId = OnDemandPalletId; +} + +impl parachains_assigner_coretime::Config for Runtime {} impl parachains_scheduler::Config for Runtime { - type AssignmentProvider = ParaAssignmentProvider; + type AssignmentProvider = CoretimeAssignmentProvider; +} + +pub struct DummyXcmSender; +impl SendXcm for DummyXcmSender { + type Ticket = (); + fn validate( + _: &mut Option, + _: &mut Option>, + ) -> SendResult { + Ok(((), Assets::new())) + } + + /// Actually carry out the delivery operation for a previously validated message sending. + fn deliver(_ticket: Self::Ticket) -> Result { + Ok([0u8; 32]) + } +} + +impl coretime::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = pallet_balances::Pallet; + type BrokerId = BrokerId; + type WeightInfo = crate::coretime::TestWeightInfo; + type SendXcm = DummyXcmSender; + type BrokerPotLocation = BrokerPot; + type AssetTransactor = (); + type AccountToLocation = (); } impl paras_sudo_wrapper::Config for Runtime {} @@ -728,7 +802,9 @@ construct_runtime! { Xcm: pallet_xcm, ParasDisputes: parachains_disputes, ParasSlashing: parachains_slashing, - ParaAssignmentProvider: parachains_assigner_parachains, + OnDemandAssignmentProvider: parachains_on_demand, + CoretimeAssignmentProvider: parachains_assigner_coretime, + Coretime: coretime, Sudo: pallet_sudo, @@ -746,8 +822,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -759,7 +835,10 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -770,7 +849,7 @@ pub type Executive = frame_executive::Executive< AllPalletsWithSystem, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; pub type Hash = ::Hash; pub type Extrinsic = ::Extrinsic; diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 28ffd9fb150a..f94301baab09 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -42,6 +42,7 @@ sp-version = { workspace = true } sp-transaction-pool = { workspace = true } sp-block-builder = { workspace = true } sp-npos-elections = { workspace = true } +sp-keyring = { workspace = true } frame-election-provider-support = { workspace = true } frame-executive = { workspace = true } @@ -68,6 +69,7 @@ pallet-identity = { workspace = true } pallet-indices = { workspace = true } pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nomination-pools = { workspace = true } @@ -118,6 +120,7 @@ xcm-builder = { 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 } @@ -167,6 +170,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nomination-pools-benchmarking?/std", @@ -257,6 +261,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks", @@ -275,6 +280,7 @@ runtime-benchmarks = [ "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", @@ -318,6 +324,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", diff --git a/polkadot/runtime/westend/src/genesis_config_presets.rs b/polkadot/runtime/westend/src/genesis_config_presets.rs index f59bacce31bd..b8f7710089e0 100644 --- a/polkadot/runtime/westend/src/genesis_config_presets.rs +++ b/polkadot/runtime/westend/src/genesis_config_presets.rs @@ -23,32 +23,19 @@ use crate::{ #[cfg(not(feature = "std"))] use alloc::format; use alloc::{vec, vec::Vec}; +use frame_support::build_struct_json_patch; use pallet_staking::{Forcing, StakerStatus}; -use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, SchedulerParams, ValidatorId}; +use polkadot_primitives::{AccountId, AssignmentId, SchedulerParams, ValidatorId}; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{sr25519, Pair, Public}; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; use sp_genesis_builder::PresetId; -use sp_runtime::{traits::IdentifyAccount, Perbill}; +use sp_keyring::Sr25519Keyring; +use sp_runtime::Perbill; use westend_runtime_constants::currency::UNITS as WND; -/// Helper function to generate a crypto pair from seed -fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed -fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - /// Helper function to generate stash, controller and session key from seed fn get_authority_keys_from_seed( seed: &str, @@ -63,7 +50,16 @@ fn get_authority_keys_from_seed( BeefyId, ) { let keys = get_authority_keys_from_seed_no_beefy(seed); - (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5, keys.6, get_from_seed::(seed)) + ( + keys.0, + keys.1, + keys.2, + keys.3, + keys.4, + keys.5, + keys.6, + get_public_from_string_or_panic::(seed), + ) } /// Helper function to generate stash, controller and session key from seed @@ -71,31 +67,18 @@ fn get_authority_keys_from_seed_no_beefy( seed: &str, ) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } fn testnet_accounts() -> Vec { - Vec::from([ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ]) + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect() } fn westend_session_keys( @@ -188,7 +171,7 @@ fn westend_testnet_genesis( 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().map(|k| (k.clone(), ENDOWMENT)).collect::>(), }, @@ -210,7 +193,6 @@ fn westend_testnet_genesis( ) }) .collect::>(), - ..Default::default() }, staking: StakingConfig { minimum_validator_count: 1, @@ -222,19 +204,12 @@ fn westend_testnet_genesis( invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), force_era: Forcing::NotForcing, 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(root_key) }, 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 }, + }) } // staging_testnet @@ -247,7 +222,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(), ]; @@ -363,7 +338,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() @@ -389,7 +364,6 @@ fn westend_staging_testnet_config_genesis() -> serde_json::Value { ) }) .collect::>(), - ..Default::default() }, staking: StakingConfig { validator_count: 50, @@ -401,26 +375,19 @@ 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 fn westend_development_config_genesis() -> serde_json::Value { westend_testnet_genesis( Vec::from([get_authority_keys_from_seed("Alice")]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -429,17 +396,17 @@ fn westend_development_config_genesis() -> serde_json::Value { fn westend_local_testnet_genesis() -> serde_json::Value { westend_testnet_genesis( Vec::from([get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } /// 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..d7281dad56d4 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -21,7 +21,7 @@ use core::marker::PhantomData; use frame_support::pallet_prelude::DispatchResult; use frame_system::RawOrigin; use polkadot_primitives::Balance; -use polkadot_runtime_common::identity_migrator::{OnReapIdentity, WeightInfo}; +use polkadot_runtime_common::identity_migrator::OnReapIdentity; use westend_runtime_constants::currency::*; use xcm::{latest::prelude::*, VersionedLocation, VersionedXcm}; use xcm_executor::traits::TransactAsset; @@ -88,10 +88,7 @@ where AccountId: Into<[u8; 32]> + Clone + Encode, { fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult { - use crate::{ - impls::IdentityMigratorCalls::PokeDeposit, - weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights, - }; + use crate::impls::IdentityMigratorCalls::PokeDeposit; let total_to_send = Self::calculate_remote_deposit(fields, subs); @@ -144,7 +141,6 @@ where .into(); let poke = PeopleRuntimePallets::::IdentityMigrator(PokeDeposit(who.clone())); - let remote_weight_limit = MigratorWeights::::poke_deposit().saturating_mul(2); // Actual program to execute on People Chain. let program: Xcm<()> = Xcm(vec![ @@ -161,18 +157,14 @@ where .into(), }, // 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(), - }, + Transact { origin_kind: OriginKind::Superuser, call: poke.encode().into() }, ]); // 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(()) } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index fe1777bc94ee..7a5562cc98c1 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::{ @@ -65,8 +66,8 @@ use polkadot_runtime_common::{ elections::OnChainAccuracy, identity_migrator, impl_runtime_weights, impls::{ - relay_era_payout, ContainsParts, EraPayoutParams, LocatableAssetConverter, ToAuthor, - VersionedLocatableAsset, VersionedLocationConverter, + ContainsParts, LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, + VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, traits::OnSwap, @@ -95,10 +96,10 @@ 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, Extrinsic as ExtrinsicT, - IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, IdentityLookup, Keccak256, + OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Percent, Permill, @@ -107,7 +108,10 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use xcm::{latest::prelude::*, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}; +use xcm::{ + latest::prelude::*, VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, + VersionedXcm, +}; use xcm_builder::PayOverXcm; use xcm_runtime_apis::{ @@ -165,8 +169,8 @@ 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, impl_version: 0, @@ -218,8 +222,10 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } parameter_types! { @@ -480,6 +486,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -536,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() @@ -681,33 +688,26 @@ impl pallet_bags_list::Config for Runtime { pub struct EraPayout; impl pallet_staking::EraPayout for EraPayout { fn era_payout( - total_staked: Balance, - total_issuance: Balance, + _total_staked: Balance, + _total_issuance: Balance, era_duration_millis: u64, ) -> (Balance, Balance) { - const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; - - let params = EraPayoutParams { - total_staked, - total_stakable: total_issuance, - ideal_stake: dynamic_params::inflation::IdealStake::get(), - max_annual_inflation: dynamic_params::inflation::MaxInflation::get(), - min_annual_inflation: dynamic_params::inflation::MinInflation::get(), - falloff: dynamic_params::inflation::Falloff::get(), - period_fraction: Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR), - legacy_auction_proportion: if dynamic_params::inflation::UseAuctionSlots::get() { - let auctioned_slots = parachains_paras::Parachains::::get() - .into_iter() - // all active para-ids that do not belong to a system chain is the number of - // parachains that we should take into account for inflation. - .filter(|i| *i >= 2000.into()) - .count() as u64; - Some(Perquintill::from_rational(auctioned_slots.min(60), 200u64)) - } else { - None - }, - }; - relay_era_payout(params) + const MILLISECONDS_PER_YEAR: u64 = (1000 * 3600 * 24 * 36525) / 100; + // A normal-sized era will have 1 / 365.25 here: + let relative_era_len = + FixedU128::from_rational(era_duration_millis.into(), MILLISECONDS_PER_YEAR.into()); + + // Fixed total TI that we use as baseline for the issuance. + let fixed_total_issuance: i128 = 5_216_342_402_773_185_773; + let fixed_inflation_rate = FixedU128::from_rational(8, 100); + let yearly_emission = fixed_inflation_rate.saturating_mul_int(fixed_total_issuance); + + let era_emission = relative_era_len.saturating_mul_int(yearly_emission); + // 15% to treasury, as per Polkadot ref 1139. + let to_treasury = FixedU128::from_rational(15, 100).saturating_mul_int(era_emission); + let to_stakers = era_emission.saturating_sub(to_treasury); + + (to_stakers.saturated_into(), to_treasury.saturated_into()) } } @@ -755,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 { @@ -824,6 +824,7 @@ impl pallet_treasury::Config for Runtime { AssetRate, >; type PayoutPeriod = PayoutSpendPeriod; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments; } @@ -860,18 +861,44 @@ impl pallet_grandpa::Config for Runtime { pallet_grandpa::EquivocationReportSystem; } +impl frame_system::offchain::SigningTypes for Runtime { + type Public = ::Signer; + type Signature = Signature; +} + +impl frame_system::offchain::CreateTransactionBase for Runtime +where + RuntimeCall: From, +{ + type RuntimeCall = RuntimeCall; + type Extrinsic = UncheckedExtrinsic; +} + +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: RuntimeCall, extension: TxExtension) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_transaction(call, extension) + } +} + /// Submits a transaction with the node's public and signature type. Adheres to the signed extension /// format of the chain. impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { use sp_runtime::traits::StaticLookup; // take the biggest period possible. let period = @@ -883,7 +910,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -896,36 +923,35 @@ where frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), frame_metadata_hash_extension::CheckMetadataHash::::new(true), - ); - let raw_payload = SignedPayload::new(call, extra) + ) + .into(); + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); + let (call, tx_ext, _) = raw_payload.deconstruct(); let address = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) + let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext); + Some(transaction) } } -impl frame_system::offchain::SigningTypes for Runtime { - type Public = ::Signer; - type Signature = Signature; -} - -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateInherent for Runtime where - RuntimeCall: From, + RuntimeCall: From, { - type OverarchingCall = RuntimeCall; - type Extrinsic = UncheckedExtrinsic; + fn create_inherent(call: RuntimeCall) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_bare(call) + } } parameter_types! { // Minimum 100 bytes/KSM deposited (1 CENT/byte) pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -938,6 +964,7 @@ impl pallet_identity::Config for Runtime { type Slashed = (); type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -948,6 +975,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; @@ -1296,7 +1324,6 @@ impl parachains_scheduler::Config for Runtime { parameter_types! { pub const BrokerId: u32 = BROKER_ID; pub const BrokerPalletId: PalletId = PalletId(*b"py/broke"); - pub MaxXcmTransactWeight: Weight = Weight::from_parts(200_000_000, 20_000); } pub struct BrokerPot; @@ -1320,7 +1347,6 @@ impl coretime::Config for Runtime { xcm_config::ThisNetwork, ::AccountId, >; - type MaxXcmTransactWeight = MaxXcmTransactWeight; } parameter_types! { @@ -1509,6 +1535,25 @@ impl pallet_root_testing::Config for Runtime { type RuntimeEvent = RuntimeEvent; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + parameter_types! { // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; @@ -1708,6 +1753,10 @@ mod runtime { #[runtime::pallet_index(66)] pub type Coretime = coretime; + // Migrations pallet + #[runtime::pallet_index(98)] + pub type MultiBlockMigrations = pallet_migrations; + // Pallet for sending XCM. #[runtime::pallet_index(99)] pub type XcmPallet = pallet_xcm; @@ -1749,8 +1798,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1786,12 +1835,20 @@ pub mod migrations { MaxAgentsToMigrate, >, parachains_shared::migration::MigrateToV1, + parachains_scheduler::migration::MigrateV2ToV3, + pallet_staking::migrations::v16::MigrateV15ToV16, + // permanent + pallet_xcm::migration::MigrateToLatestXcmVersion, ); } /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; + /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -1802,7 +1859,7 @@ pub type Executive = frame_executive::Executive< Migrations, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; #[cfg(feature = "runtime-benchmarks")] mod benches { @@ -1837,6 +1894,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] @@ -1851,7 +1909,9 @@ mod benches { [pallet_staking, Staking] [pallet_sudo, Sudo] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -2434,15 +2494,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) } @@ -2450,7 +2510,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) } @@ -2462,9 +2522,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 { @@ -2515,6 +2579,7 @@ sp_api::impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; @@ -2531,7 +2596,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}; @@ -2543,6 +2608,7 @@ sp_api::impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; impl pallet_session_benchmarking::Config for Runtime {} @@ -2763,4 +2829,13 @@ sp_api::impl_runtime_apis! { genesis_config_presets::preset_names() } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_teleporter(asset, location) + } + } } diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index eef95006bce4..02fd6b61496b 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -19,11 +19,15 @@ use std::collections::HashSet; use crate::{xcm_config::LocationConverter, *}; +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 xcm_runtime_apis::conversions::LocationToAccountHelper; +const MILLISECONDS_PER_HOUR: u64 = 60 * 60 * 1000; + #[test] fn remove_keys_weight_is_sensible() { use polkadot_runtime_common::crowdloan::WeightInfo; @@ -64,7 +68,7 @@ fn sanity_check_teleport_assets_weight() { weight_limit: Unlimited, } .get_dispatch_info() - .weight; + .call_weight; assert!((weight * 50).all_lt(BlockWeights::get().max_block)); } @@ -311,3 +315,94 @@ fn location_conversion_works() { assert_eq!(got, expected, "{}", tc.description); } } + +#[test] +fn staking_inflation_correct_single_era() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + MILLISECONDS_PER_HOUR, + ); + + assert_relative_eq!(to_stakers as f64, (4_046 * CENTS) as f64, max_relative = 0.01); + assert_relative_eq!(to_treasury as f64, (714 * CENTS) as f64, max_relative = 0.01); + // Total per hour is ~47.6 WND + assert_relative_eq!( + (to_stakers as f64 + to_treasury as f64), + (4_760 * CENTS) as f64, + max_relative = 0.001 + ); +} + +#[test] +fn staking_inflation_correct_longer_era() { + // Twice the era duration means twice the emission: + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + 2 * MILLISECONDS_PER_HOUR, + ); + + assert_relative_eq!(to_stakers as f64, (4_046 * CENTS) as f64 * 2.0, max_relative = 0.001); + assert_relative_eq!(to_treasury as f64, (714 * CENTS) as f64 * 2.0, max_relative = 0.001); +} + +#[test] +fn staking_inflation_correct_whole_year() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + (36525 * 24 * MILLISECONDS_PER_HOUR) / 100, // 1 year + ); + + // Our yearly emissions is about 417k WND: + let yearly_emission = 417_307 * UNITS; + assert_relative_eq!( + to_stakers as f64 + to_treasury as f64, + yearly_emission as f64, + max_relative = 0.001 + ); + + assert_relative_eq!(to_stakers as f64, yearly_emission as f64 * 0.85, max_relative = 0.001); + assert_relative_eq!(to_treasury as f64, yearly_emission as f64 * 0.15, max_relative = 0.001); +} + +// 10 years into the future, our values do not overflow. +#[test] +fn staking_inflation_correct_not_overflow() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + (36525 * 24 * MILLISECONDS_PER_HOUR) / 10, // 10 years + ); + let initial_ti: i128 = 5_216_342_402_773_185_773; + let projected_total_issuance = (to_stakers as i128 + to_treasury as i128) + initial_ti; + + // In 2034, there will be about 9.39 million WND in existence. + assert_relative_eq!( + projected_total_issuance as f64, + (9_390_000 * UNITS) as f64, + max_relative = 0.001 + ); +} + +// Print percent per year, just as convenience. +#[test] +fn staking_inflation_correct_print_percent() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + (36525 * 24 * MILLISECONDS_PER_HOUR) / 100, // 1 year + ); + let yearly_emission = to_stakers + to_treasury; + let mut ti: i128 = 5_216_342_402_773_185_773; + + for y in 0..10 { + let new_ti = ti + yearly_emission as i128; + let inflation = 100.0 * (new_ti - ti) as f64 / ti as f64; + println!("Year {y} inflation: {inflation}%"); + ti = new_ti; + + assert!(inflation <= 8.0 && inflation > 2.0, "sanity check"); + } +} diff --git a/polkadot/runtime/westend/src/weights/frame_system_extensions.rs b/polkadot/runtime/westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..048f23fbcb91 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,131 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-12, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot +// benchmark +// pallet +// --steps=2 +// --repeat=2 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=frame-system-extensions +// --chain=westend-dev +// --output=./polkadot/runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// 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` + // Estimated: `3509` + // Minimum execution time: 75_764_000 picoseconds. + Weight::from_parts(85_402_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 118_233_000 picoseconds. + Weight::from_parts(126_539_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// 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` + // Estimated: `3509` + // Minimum execution time: 118_233_000 picoseconds. + Weight::from_parts(126_539_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_885_000 picoseconds. + Weight::from_parts(12_784_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 104_237_000 picoseconds. + Weight::from_parts(110_910_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_141_000 picoseconds. + Weight::from_parts(11_502_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_192_000 picoseconds. + Weight::from_parts(11_481_000, 0) + .saturating_add(Weight::from_parts(0, 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: 87_616_000 picoseconds. + Weight::from_parts(93_607_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index ae11f6ccba41..efd18b38545a 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -17,6 +17,7 @@ pub mod frame_election_provider_support; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_asset_rate; pub mod pallet_bags_list; pub mod pallet_balances; @@ -27,6 +28,7 @@ pub mod pallet_fast_unstake; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nomination_pools; @@ -39,6 +41,7 @@ pub mod pallet_session; pub mod pallet_staking; pub mod pallet_sudo; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; diff --git a/polkadot/runtime/westend/src/weights/pallet_identity.rs b/polkadot/runtime/westend/src/weights/pallet_identity.rs index dc7061615c95..60899dd4d173 100644 --- a/polkadot/runtime/westend/src/weights/pallet_identity.rs +++ b/polkadot/runtime/westend/src/weights/pallet_identity.rs @@ -366,7 +366,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, 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() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -394,7 +394,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -418,18 +418,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/polkadot/runtime/westend/src/weights/pallet_migrations.rs b/polkadot/runtime/westend/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..4fa07a23bb8a --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_migrations.rs @@ -0,0 +1,173 @@ +// 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 . + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .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`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// 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) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_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: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // 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())) + .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()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/polkadot/runtime/westend/src/weights/pallet_sudo.rs b/polkadot/runtime/westend/src/weights/pallet_sudo.rs index e9ab3ad37a4c..649c43e031dc 100644 --- a/polkadot/runtime/westend/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/westend/src/weights/pallet_sudo.rs @@ -94,4 +94,15 @@ impl pallet_sudo::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Sudo::Key` (r:1 w:0) + /// 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: `132` + // Estimated: `1517` + // Minimum execution time: 2_875_000 picoseconds. + Weight::from_parts(6_803_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs b/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..71a01b6a0c2e --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,68 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-12, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot +// benchmark +// pallet +// --steps=2 +// --repeat=2 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet-transaction-payment +// --chain=westend-dev +// --output=./polkadot/runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, 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_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `3593` + // Minimum execution time: 569_518_000 picoseconds. + Weight::from_parts(590_438_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs index 32f6f28f2426..36aafc1d2f2a 100644 --- a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `polkadot_runtime_parachains::paras_inherent` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-17, 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-dr4vwrkf-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,10 +54,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -70,23 +72,21 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn enter_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `37553` - // Estimated: `41018` - // Minimum execution time: 237_414_000 picoseconds. - Weight::from_parts(245_039_000, 0) - .saturating_add(Weight::from_parts(0, 41018)) + // Measured: `37559` + // Estimated: `41024` + // Minimum execution time: 217_257_000 picoseconds. + Weight::from_parts(228_878_000, 0) + .saturating_add(Weight::from_parts(0, 41024)) .saturating_add(T::DbWeight::get().reads(15)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -94,10 +94,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -134,16 +136,14 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::Heads` (r:0 w:1) @@ -152,19 +152,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[10, 1024]`. + /// The range of component `v` is `[400, 1024]`. fn enter_variable_disputes(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `199504` - // Estimated: `205444 + v * (5 ±0)` - // Minimum execution time: 1_157_489_000 picoseconds. - Weight::from_parts(629_243_559, 0) - .saturating_add(Weight::from_parts(0, 205444)) - // Standard Error: 10_997 - .saturating_add(Weight::from_parts(50_752_930, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(16)) - .saturating_add(Weight::from_parts(0, 5).saturating_mul(v.into())) + // Measured: `117547` + // Estimated: `123487` + // Minimum execution time: 21_077_090_000 picoseconds. + Weight::from_parts(703_350_265, 0) + .saturating_add(Weight::from_parts(0, 123487)) + // Standard Error: 21_944 + .saturating_add(Weight::from_parts(51_197_317, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(29)) + .saturating_add(T::DbWeight::get().writes(17)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -172,10 +171,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -188,25 +189,21 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn enter_bitfields() -> Weight { // Proof Size summary in bytes: - // Measured: `75131` - // Estimated: `81071` - // Minimum execution time: 466_928_000 picoseconds. - Weight::from_parts(494_342_000, 0) - .saturating_add(Weight::from_parts(0, 81071)) - .saturating_add(T::DbWeight::get().reads(17)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `74967` + // Estimated: `80907` + // Minimum execution time: 487_605_000 picoseconds. + Weight::from_parts(506_014_000, 0) + .saturating_add(Weight::from_parts(0, 80907)) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -214,10 +211,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -248,12 +247,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:0) @@ -264,6 +259,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -277,15 +274,15 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// The range of component `v` is `[2, 5]`. fn enter_backed_candidates_variable(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `76369` - // Estimated: `82309` - // Minimum execution time: 1_468_919_000 picoseconds. - Weight::from_parts(1_433_315_477, 0) - .saturating_add(Weight::from_parts(0, 82309)) - // Standard Error: 419_886 - .saturating_add(Weight::from_parts(42_880_485, 0).saturating_mul(v.into())) + // Measured: `76491` + // Estimated: `82431` + // Minimum execution time: 1_496_985_000 picoseconds. + Weight::from_parts(1_466_448_265, 0) + .saturating_add(Weight::from_parts(0, 82431)) + // Standard Error: 403_753 + .saturating_add(Weight::from_parts(44_015_233, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(29)) - .saturating_add(T::DbWeight::get().writes(16)) + .saturating_add(T::DbWeight::get().writes(15)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -293,10 +290,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -327,12 +326,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::FutureCodeHash` (r:1 w:0) @@ -347,6 +342,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -359,12 +356,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_backed_candidate_code_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `76382` - // Estimated: `82322` - // Minimum execution time: 34_577_233_000 picoseconds. - Weight::from_parts(39_530_352_000, 0) - .saturating_add(Weight::from_parts(0, 82322)) + // Measured: `76504` + // Estimated: `82444` + // Minimum execution time: 40_136_167_000 picoseconds. + Weight::from_parts(41_572_376_000, 0) + .saturating_add(Weight::from_parts(0, 82444)) .saturating_add(T::DbWeight::get().reads(31)) - .saturating_add(T::DbWeight::get().writes(16)) + .saturating_add(T::DbWeight::get().writes(15)) } } diff --git a/polkadot/runtime/westend/src/weights/xcm/mod.rs b/polkadot/runtime/westend/src/weights/xcm/mod.rs index cb5894ea51e3..5be9bad824da 100644 --- a/polkadot/runtime/westend/src/weights/xcm/mod.rs +++ b/polkadot/runtime/westend/src/weights/xcm/mod.rs @@ -27,6 +27,7 @@ use xcm::{ use pallet_xcm_benchmarks_fungible::WeightInfo as XcmBalancesWeight; use pallet_xcm_benchmarks_generic::WeightInfo as XcmGeneric; +use xcm::latest::AssetTransferFilter; /// Types of asset supported by the westend runtime. pub enum AssetTypes { @@ -113,11 +114,7 @@ impl XcmWeightInfo for WestendXcmWeight { fn transfer_reserve_asset(assets: &Assets, _dest: &Location, _xcm: &Xcm<()>) -> Weight { assets.weigh_assets(XcmBalancesWeight::::transfer_reserve_asset()) } - fn transact( - _origin_kind: &OriginKind, - _require_weight_at_most: &Weight, - _call: &DoubleEncoded, - ) -> Weight { + fn transact(_origin_kind: &OriginKind, _call: &DoubleEncoded) -> Weight { XcmGeneric::::transact() } fn hrmp_new_channel_open_request( @@ -166,12 +163,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 +204,11 @@ impl XcmWeightInfo for WestendXcmWeight { fn clear_error() -> Weight { XcmGeneric::::clear_error() } + + fn set_asset_claimer(_location: &Location) -> Weight { + XcmGeneric::::set_asset_claimer() + } + fn claim_asset(_assets: &Assets, _ticket: &Location) -> Weight { XcmGeneric::::claim_asset() } @@ -269,6 +294,9 @@ impl XcmWeightInfo for WestendXcmWeight { 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..076744a59753 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,11 +16,11 @@ //! 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("westend-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-vcatxqpx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 // Executed Command: // target/production/polkadot @@ -29,14 +29,14 @@ // --steps=50 // --repeat=20 // --extrinsic=* -// --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --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/ +// --header=./polkadot/file_header.txt +// --template=./polkadot/xcm/pallet-xcm-benchmarks/template.hbs +// --output=./polkadot/runtime/westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -49,126 +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: 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: 69_051_000 picoseconds. + Weight::from_parts(71_282_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: 660_000 picoseconds. + Weight::from_parts(695_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_096_000 picoseconds. + Weight::from_parts(3_313_000, 0) + } + pub(crate) fn set_asset_claimer() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 661_000 picoseconds. + Weight::from_parts(707_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_054_000 picoseconds. + Weight::from_parts(6_151_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_462_000 picoseconds. + Weight::from_parts(7_750_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_378_000 picoseconds. + Weight::from_parts(1_454_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: 660_000 picoseconds. + Weight::from_parts(744_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: 713_000 picoseconds. + Weight::from_parts(755_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: 632_000 picoseconds. + Weight::from_parts(703_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: 712_000 picoseconds. + Weight::from_parts(771_000, 0) + } + pub(crate) fn execute_with_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 740_000 picoseconds. + Weight::from_parts(826_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) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(707_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) + /// 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: 66_765_000 picoseconds. + Weight::from_parts(69_016_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_545_000 picoseconds. + Weight::from_parts(9_853_000, 3488) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -176,165 +189,151 @@ 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) + // Minimum execution time: 676_000 picoseconds. + Weight::from_parts(723_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) + /// 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: 31_324_000 picoseconds. + Weight::from_parts(32_023_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_058_000 picoseconds. + Weight::from_parts(3_199_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: 994_000 picoseconds. + Weight::from_parts(1_115_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: 763_000 picoseconds. + Weight::from_parts(824_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: 665_000 picoseconds. + Weight::from_parts(712_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: 627_000 picoseconds. + Weight::from_parts(695_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) + // Minimum execution time: 839_000 picoseconds. + Weight::from_parts(889_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) + /// 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: 75_853_000 picoseconds. + Weight::from_parts(77_515_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) + // Minimum execution time: 8_183_000 picoseconds. + Weight::from_parts(8_378_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) + /// 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: 66_576_000 picoseconds. + Weight::from_parts(69_465_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: 739_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_494_000 picoseconds. - Weight::from_parts(2_588_000, 0) + // Minimum execution time: 648_000 picoseconds. + Weight::from_parts(693_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: 654_000 picoseconds. + Weight::from_parts(700_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: 646_000 picoseconds. + Weight::from_parts(702_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: 665_000 picoseconds. + Weight::from_parts(714_000, 0) } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index d75083929a04..f8bb2676de3f 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -36,7 +36,7 @@ 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, @@ -51,7 +51,7 @@ 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); 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 469c877eafc9..c8ad28437f88 100644 --- a/polkadot/statement-table/src/lib.rs +++ b/polkadot/statement-table/src/lib.rs @@ -29,14 +29,14 @@ pub mod generic; -pub use generic::{Config, Context, Table}; +pub use generic::{Context, Table}; /// Concrete instantiations suitable for v2 primitives. pub mod v2 { use crate::generic; use polkadot_primitives::{ - CandidateHash, CommittedCandidateReceipt, CompactStatement as PrimitiveStatement, - CoreIndex, ValidatorIndex, ValidatorSignature, + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateHash, + CompactStatement as PrimitiveStatement, CoreIndex, ValidatorIndex, ValidatorSignature, }; /// Statements about candidates on the network. diff --git a/polkadot/tests/benchmark_overhead.rs b/polkadot/tests/benchmark_overhead.rs index b0912225347d..51f507450f38 100644 --- a/polkadot/tests/benchmark_overhead.rs +++ b/polkadot/tests/benchmark_overhead.rs @@ -29,14 +29,6 @@ fn benchmark_overhead_works() { } } -/// `benchmark overhead` rejects all non-dev runtimes. -#[test] -fn benchmark_overhead_rejects_non_dev_runtimes() { - for runtime in RUNTIMES.into_iter() { - assert!(benchmark_overhead(runtime).is_err()); - } -} - fn benchmark_overhead(runtime: &str) -> Result<(), String> { let tmp_dir = tempdir().expect("could not create a temp dir"); let base_path = tmp_dir.path(); diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 862f5557a012..86c7067ad6fa 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -23,11 +23,12 @@ 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 } +hex-literal = { workspace = true, default-features = true } +frame-support = { workspace = true } [dev-dependencies] sp-io = { workspace = true, default-features = true } hex = { workspace = true, default-features = true } -hex-literal = { workspace = true, default-features = true } [features] default = ["std"] @@ -36,6 +37,7 @@ std = [ "bounded-collections/std", "codec/std", "environmental/std", + "frame-support/std", "log/std", "scale-info/std", "serde/std", 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 7cb230f6e006..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, @@ -168,7 +168,7 @@ impl pallet_xcm::Config for Runtime { type UniversalLocation = UniversalLocation; // No version discovery needed const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0; - type AdvertisedXcmVersion = frame::traits::ConstU32<3>; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type AdminOrigin = frame_system::EnsureRoot; // No locking type TrustedLockers = (); 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 a31e664d8216..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, @@ -142,7 +142,7 @@ impl pallet_xcm::Config for Runtime { type UniversalLocation = UniversalLocation; // No version discovery needed const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0; - type AdvertisedXcmVersion = frame::traits::ConstU32<3>; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type AdminOrigin = frame_system::EnsureRoot; // No locking type TrustedLockers = (); 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/src/fungible/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/benchmarking.rs index 6ce49074a6e2..303ff9493f71 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! { @@ -299,6 +299,33 @@ 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 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: T::valid_destination()?, + // 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 40a7da58a687..87bf27e4ff18 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -19,7 +19,7 @@ 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_support::traits::fungible::Inspect; use xcm::{ latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight, MAX_ITEMS_IN_ASSETS}, DoubleEncoded, @@ -98,6 +98,36 @@ benchmarks! { } + pay_fees { + 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]); + } : { + executor.bench_process(xcm)?; + } verify {} + + set_asset_claimer { + let mut executor = new_executor::(Default::default()); + let (_, sender_location) = account_and_location::(1); + + let instruction = Instruction::SetAssetClaimer{ location:sender_location.clone() }; + + let xcm = Xcm(vec![instruction]); + }: { + executor.bench_process(xcm)?; + } verify { + assert_eq!(executor.asset_claimer(), Some(sender_location.clone())); + } + query_response { let mut executor = new_executor::(Default::default()); let (query_id, response) = T::worst_case_response(); @@ -121,7 +151,6 @@ benchmarks! { let instruction = Instruction::Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: noop_call.get_dispatch_info().weight, call: double_encoded_noop_call, }; let xcm = Xcm(vec![instruction]); @@ -200,6 +229,23 @@ benchmarks! { ); } + execute_with_origin { + 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]); + }: { + executor.bench_process(xcm)?; + } verify { + assert_eq!( + executor.origin(), + &Some(Location { + parents: 0, + interior: Here, + }), + ); + } + clear_origin { let mut executor = new_executor::(Default::default()); let instruction = Instruction::ClearOrigin; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index 210b8f656377..5f8482bdcb8c 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -62,7 +62,7 @@ const SEED: u32 = 0; /// The XCM executor to use for doing stuff. pub type ExecutorOf = xcm_executor::XcmExecutor<::XcmConfig>; /// The overarching call type. -pub type OverArchingCallOf = ::RuntimeCall; +pub type RuntimeCallOf = ::RuntimeCall; /// The asset transactor of our executor pub type AssetTransactorOf = <::XcmConfig as XcmConfig>::AssetTransactor; /// The call type of executor's config. Should eventually resolve to the same overarching call type. diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index ed4b441d7c33..4d44d75e34dd 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -14,7 +14,7 @@ bounded-collections = { workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } -log = { workspace = true } +tracing = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } @@ -44,13 +44,13 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", - "log/std", "pallet-balances/std", "scale-info/std", "serde", "sp-core/std", "sp-io/std", "sp-runtime/std", + "tracing/std", "xcm-builder/std", "xcm-executor/std", "xcm-runtime-apis/std", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index d09c81bf434e..e493d4838f5c 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -128,14 +128,14 @@ benchmarks! { &origin_location, None, ).map_err(|error| { - log::error!("Fungible asset couldn't be deposited, error: {:?}", 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| { - log::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; } @@ -178,14 +178,14 @@ benchmarks! { &origin_location, None, ).map_err(|error| { - log::error!("Fungible asset couldn't be deposited, error: {:?}", 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| { - log::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; } @@ -382,8 +382,8 @@ benchmarks! { asset.clone().into(), &XcmContext { origin: None, message_id: [0u8; 32], topic: None } ); - let versioned_assets = VersionedAssets::V4(asset.into()); - }: _>(claim_origin.into(), Box::new(versioned_assets), Box::new(VersionedLocation::V4(claim_location))) + let versioned_assets = VersionedAssets::from(Assets::from(asset)); + }: _>(claim_origin.into(), Box::new(versioned_assets), Box::new(VersionedLocation::from(claim_location))) impl_benchmark_test_suite!( Pallet, diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index ee448c3df606..5e0512c6a9fd 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -70,10 +70,12 @@ use xcm_executor::{ use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, + trusted_query::Error as TrustedQueryApiError, }; #[cfg(any(feature = "try-runtime", test))] use sp_runtime::TryRuntimeError; +use xcm_executor::traits::{FeeManager, FeeReason}; pub trait WeightInfo { fn send() -> Weight; @@ -239,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)>; @@ -307,7 +309,7 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> Result { - log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); + tracing::trace!(target: "xcm::pallet_xcm::execute", ?message, ?max_weight); let outcome = (|| { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let mut hash = message.using_encoded(sp_io::hashing::blake2_256); @@ -330,7 +332,7 @@ pub mod pallet { Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); let weight_used = outcome.weight_used(); outcome.ensure_complete().map_err(|error| { - log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error); + tracing::error!(target: "xcm::pallet_xcm::execute", ?error, "XCM execution failed with error"); Error::::LocalExecutionIncomplete.with_weight( weight_used.saturating_add( ::execute(), @@ -897,10 +899,10 @@ pub mod pallet { pub fn migrate_to_v1( ) -> frame_support::weights::Weight { let on_chain_storage_version =

::on_chain_storage_version(); - log::info!( + tracing::info!( target: "runtime::xcm", - "Running migration storage v1 for xcm with storage version {:?}", - on_chain_storage_version, + ?on_chain_storage_version, + "Running migration storage v1 for xcm with storage version", ); if on_chain_storage_version < 1 { @@ -910,18 +912,18 @@ pub mod pallet { Some(value.into()) }); StorageVersion::new(1).put::

(); - log::info!( + tracing::info!( target: "runtime::xcm", - "Running migration storage v1 for xcm with storage version {:?} was complete", - on_chain_storage_version, + ?on_chain_storage_version, + "Running migration storage v1 for xcm with storage version was complete", ); // calculate and return migration weights T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) } else { - log::warn!( + tracing::warn!( target: "runtime::xcm", - "Attempted to apply migration to v1 but failed because storage version is {:?}", - on_chain_storage_version, + ?on_chain_storage_version, + "Attempted to apply migration to v1 but failed because storage version is", ); T::DbWeight::get().reads(1) } @@ -1269,10 +1271,9 @@ pub mod pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::transfer_assets", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}", - origin, dest, beneficiary, assets, fee_asset_item, weight_limit, + ?origin, ?dest, ?beneficiary, ?assets, ?fee_asset_item, ?weight_limit, ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); @@ -1307,7 +1308,7 @@ pub mod pallet { beneficiary: Box, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - log::debug!(target: "xcm::pallet_xcm::claim_assets", "origin: {:?}, assets: {:?}, beneficiary: {:?}", origin_location, assets, beneficiary); + tracing::debug!(target: "xcm::pallet_xcm::claim_assets", ?origin_location, ?assets, ?beneficiary); // Extract version from `assets`. let assets_version = assets.identify_version(); let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; @@ -1330,7 +1331,7 @@ pub mod pallet { weight, ); outcome.ensure_complete().map_err(|error| { - log::error!(target: "xcm::pallet_xcm::claim_assets", "XCM execution failed with error: {:?}", error); + tracing::error!(target: "xcm::pallet_xcm::claim_assets", ?error, "XCM execution failed with error"); Error::::LocalExecutionIncomplete })?; Ok(()) @@ -1403,11 +1404,10 @@ pub mod pallet { (*remote_fees_id).try_into().map_err(|()| Error::::BadVersion)?; let remote_xcm: Xcm<()> = (*custom_xcm_on_dest).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::transfer_assets_using_type_and_then", - "origin {origin_location:?}, dest {dest:?}, assets {assets:?} through {assets_transfer_type:?}, \ - remote_fees_id {fees_id:?} through {fees_transfer_type:?}, \ - custom_xcm_on_dest {remote_xcm:?}, weight-limit {weight_limit:?}", + ?origin_location, ?dest, ?assets, ?assets_transfer_type, ?fees_id, ?fees_transfer_type, + ?remote_xcm, ?weight_limit, ); let assets = assets.into_inner(); @@ -1568,10 +1568,9 @@ impl Pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::do_reserve_transfer_assets", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}", - origin_location, dest, beneficiary, assets, fee_asset_item, + ?origin_location, ?dest, ?beneficiary, ?assets, ?fee_asset_item, ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); @@ -1615,10 +1614,9 @@ impl Pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::do_teleport_assets", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}", - origin_location, dest, beneficiary, assets, fee_asset_item, weight_limit, + ?origin_location, ?dest, ?beneficiary, ?assets, ?fee_asset_item, ?weight_limit, ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); @@ -1719,11 +1717,9 @@ impl Pallet { fees: FeesHandling, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Option>), Error> { - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::build_xcm_transfer_type", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ - fees_handling {:?}, weight_limit: {:?}", - origin, dest, beneficiary, assets, transfer_type, fees, weight_limit, + ?origin, ?dest, ?beneficiary, ?assets, ?transfer_type, ?fees, ?weight_limit, ); match transfer_type { TransferType::LocalReserve => Self::local_reserve_transfer_programs( @@ -1778,10 +1774,9 @@ impl Pallet { mut local_xcm: Xcm<::RuntimeCall>, remote_xcm: Option>, ) -> DispatchResult { - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::execute_xcm_transfer", - "origin {:?}, dest {:?}, local_xcm {:?}, remote_xcm {:?}", - origin, dest, local_xcm, remote_xcm, + ?origin, ?dest, ?local_xcm, ?remote_xcm, ); let weight = @@ -1795,10 +1790,10 @@ impl Pallet { weight, ); Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); - outcome.ensure_complete().map_err(|error| { - log::error!( + outcome.clone().ensure_complete().map_err(|error| { + tracing::error!( target: "xcm::pallet_xcm::execute_xcm_transfer", - "XCM execution failed with error {:?}", error + ?error, "XCM execution failed with error with outcome: {:?}", outcome ); Error::::LocalExecutionIncomplete })?; @@ -1807,10 +1802,10 @@ impl Pallet { let (ticket, price) = validate_send::(dest.clone(), remote_xcm.clone()) .map_err(Error::::from)?; if origin != Here.into_location() { - Self::charge_fees(origin.clone(), price).map_err(|error| { - log::error!( + Self::charge_fees(origin.clone(), price.clone()).map_err(|error| { + tracing::error!( target: "xcm::pallet_xcm::execute_xcm_transfer", - "Unable to charge fee with error {:?}", error + ?error, ?price, ?origin, "Unable to charge fee", ); Error::::FeesNotMet })?; @@ -1836,7 +1831,10 @@ impl Pallet { // no custom fees instructions, they are batched together with `assets` transfer; // BuyExecution happens after receiving all `assets` let reanchored_fees = - fees.reanchored(&dest, &context).map_err(|_| Error::::CannotReanchor)?; + fees.reanchored(&dest, &context).map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::add_fees_to_xcm", ?e, ?dest, ?context, "Failed to re-anchor fees"); + Error::::CannotReanchor + })?; // buy execution using `fees` batched together with above `reanchored_assets` remote.inner_mut().push(BuyExecution { fees: reanchored_fees, weight_limit }); }, @@ -1901,7 +1899,10 @@ impl Pallet { let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::local_reserve_transfer_programs", ?e, ?dest, ?context, "Failed to re-anchor assets"); + Error::::CannotReanchor + })?; // XCM instructions to be executed on local chain let mut local_execute_xcm = Xcm(vec![ @@ -1948,7 +1949,10 @@ impl Pallet { let reanchored_fees = fees .clone() .reanchored(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::destination_reserve_fees_instructions", ?e, ?dest,?context, "Failed to re-anchor fees"); + Error::::CannotReanchor + })?; let fees: Assets = fees.into(); let local_execute_xcm = Xcm(vec![ @@ -1992,7 +1996,10 @@ impl Pallet { let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::destination_reserve_transfer_programs", ?e, ?dest, ?context, "Failed to re-anchor assets"); + Error::::CannotReanchor + })?; // XCM instructions to be executed on local chain let mut local_execute_xcm = Xcm(vec![ @@ -2046,13 +2053,22 @@ impl Pallet { // identifies fee item as seen by `reserve` - to be used at reserve chain let reserve_fees = fees_half_1 .reanchored(&reserve, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::remote_reserve_transfer_program", ?e, ?reserve, ?context, "Failed to re-anchor reserve_fees"); + Error::::CannotReanchor + })?; // identifies fee item as seen by `dest` - to be used at destination chain let dest_fees = fees_half_2 .reanchored(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::remote_reserve_transfer_program", ?e, ?dest, ?context, "Failed to re-anchor dest_fees"); + Error::::CannotReanchor + })?; // identifies `dest` as seen by `reserve` - let dest = dest.reanchored(&reserve, &context).map_err(|_| Error::::CannotReanchor)?; + let dest = dest.reanchored(&reserve, &context).map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::remote_reserve_transfer_program", ?e, ?reserve, ?context, "Failed to re-anchor dest"); + Error::::CannotReanchor + })?; // xcm to be executed at dest let mut xcm_on_dest = Xcm(vec![BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() }]); @@ -2098,7 +2114,10 @@ impl Pallet { let reanchored_fees = fees .clone() .reanchored(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_fees_instructions", ?e, ?dest, ?context, "Failed to re-anchor fees"); + Error::::CannotReanchor + })?; // XcmContext irrelevant in teleports checks let dummy_context = @@ -2112,7 +2131,10 @@ impl Pallet { &fees, &dummy_context, ) - .map_err(|_| Error::::CannotCheckOutTeleport)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_fees_instructions", ?e, ?fees, ?dest, "Failed can_check_out"); + Error::::CannotCheckOutTeleport + })?; // safe to do this here, we're in a transactional call that will be reverted on any // errors down the line ::AssetTransactor::check_out( @@ -2163,7 +2185,10 @@ impl Pallet { let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_assets_program", ?e, ?dest, ?context, "Failed to re-anchor asset"); + Error::::CannotReanchor + })?; // XcmContext irrelevant in teleports checks let dummy_context = @@ -2178,7 +2203,10 @@ impl Pallet { asset, &dummy_context, ) - .map_err(|_| Error::::CannotCheckOutTeleport)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_assets_program", ?e, ?asset, ?dest, "Failed can_check_out asset"); + Error::::CannotCheckOutTeleport + })?; } for asset in assets.inner() { // safe to do this here, we're in a transactional call that will be reverted on any @@ -2441,17 +2469,24 @@ 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 - }; - log::debug!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); + } + 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(|_| SendError::Fees)?; + if !is_waived { + Self::charge_fees(local_origin, price).map_err(|e| { + tracing::error!( + target: "xcm::pallet_xcm::send_xcm", + ?e, + "Charging fees failed with error", + ); + SendError::Fees + })?; } T::XcmRouter::deliver(ticket) } @@ -2502,7 +2537,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> @@ -2512,18 +2547,16 @@ impl Pallet { XcmConfig: xcm_executor::Config, { let origin_location: Location = origin_location.try_into().map_err(|error| { - log::error!( + tracing::error!( target: "xcm::DryRunApi::dry_run_xcm", - "Location version conversion failed with error: {:?}", - error, + ?error, "Location version conversion failed with error" ); XcmDryRunApiError::VersionedConversionFailed })?; let xcm: Xcm = xcm.try_into().map_err(|error| { - log::error!( + tracing::error!( target: "xcm::DryRunApi::dry_run_xcm", - "Xcm version conversion failed with error {:?}", - error, + ?error, "Xcm version conversion failed with error" ); XcmDryRunApiError::VersionedConversionFailed })?; @@ -2560,36 +2593,100 @@ impl Pallet { } pub fn query_xcm_weight(message: VersionedXcm<()>) -> Result { - let message = Xcm::<()>::try_from(message) - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + let message = Xcm::<()>::try_from(message.clone()) + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_xcm_weight", ?e, ?message, "Failed to convert versioned message"); + XcmPaymentApiError::VersionedConversionFailed + })?; - T::Weigher::weight(&mut message.into()).map_err(|()| { - log::error!(target: "xcm::pallet_xcm::query_xcm_weight", "Error when querying XCM weight"); + T::Weigher::weight(&mut message.clone().into()).map_err(|()| { + tracing::error!(target: "xcm::pallet_xcm::query_xcm_weight", ?message, "Error when querying XCM weight"); XcmPaymentApiError::WeightNotComputable }) } + /// Given an Asset and a Location, returns if the provided location is a trusted reserve for the + /// given asset. + pub fn is_trusted_reserve( + asset: VersionedAsset, + location: VersionedLocation, + ) -> Result { + let location: Location = location.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_reserve", + "Asset version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedLocationConversionFailed + })?; + + let a: Asset = asset.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_reserve", + "Location version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedAssetConversionFailed + })?; + + Ok(::IsReserve::contains(&a, &location)) + } + + /// Given an Asset and a Location, returns if the asset can be teleported to provided location. + pub fn is_trusted_teleporter( + asset: VersionedAsset, + location: VersionedLocation, + ) -> Result { + let location: Location = location.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_teleporter", + "Asset version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedLocationConversionFailed + })?; + let a: Asset = asset.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_teleporter", + "Location version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedAssetConversionFailed + })?; + Ok(::IsTeleporter::contains(&a, &location)) + } + pub fn query_delivery_fees( destination: VersionedLocation, message: VersionedXcm<()>, ) -> Result { let result_version = destination.identify_version().max(message.identify_version()); - let destination = destination + let destination: Location = destination + .clone() .try_into() - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?destination, "Failed to convert versioned destination"); + XcmPaymentApiError::VersionedConversionFailed + })?; - let message = - message.try_into().map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + let message: Xcm<()> = + message.clone().try_into().map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?message, "Failed to convert versioned message"); + XcmPaymentApiError::VersionedConversionFailed + })?; - let (_, fees) = validate_send::(destination, message).map_err(|error| { - log::error!(target: "xcm::pallet_xcm::query_delivery_fees", "Error when querying delivery fees: {:?}", error); + let (_, fees) = validate_send::(destination.clone(), message.clone()).map_err(|error| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?error, ?destination, ?message, "Failed to validate send to destination"); XcmPaymentApiError::Unroutable })?; VersionedAssets::from(fees) .into_version(result_version) - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed) + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?result_version, "Failed to convert fees into version"); + XcmPaymentApiError::VersionedConversionFailed + }) } /// Create a new expectation of a query response with the querier being here. @@ -2648,7 +2745,7 @@ impl Pallet { .invert_target(&responder) .map_err(|()| XcmError::LocationNotInvertible)?; let notify: ::RuntimeCall = notify.into(); - let max_weight = notify.get_dispatch_info().weight; + let max_weight = notify.get_dispatch_info().call_weight; let query_id = Self::new_notify_query(responder, notify, timeout, Here); let response_info = QueryResponseInfo { destination, query_id, max_weight }; let report_error = Xcm(vec![ReportError(response_info)]); @@ -2673,10 +2770,9 @@ impl Pallet { /// Note that a particular destination to whom we would like to send a message is unknown /// and queue it for version discovery. fn note_unknown_version(dest: &Location) { - log::trace!( + tracing::trace!( target: "xcm::pallet_xcm::note_unknown_version", - "XCM version is unknown for destination: {:?}", - dest, + ?dest, "XCM version is unknown for destination" ); let versioned_dest = VersionedLocation::from(dest.clone()); VersionDiscoveryQueue::::mutate(|q| { @@ -2712,6 +2808,44 @@ impl Pallet { /// set. #[cfg(any(feature = "try-runtime", test))] pub fn do_try_state() -> Result<(), TryRuntimeError> { + use migration::data::NeedsMigration; + + // Take the minimum version between `SafeXcmVersion` and `latest - 1` and ensure that the + // operational data is stored at least at that version, for example, to prevent issues when + // removing older XCM versions. + let minimal_allowed_xcm_version = if let Some(safe_xcm_version) = SafeXcmVersion::::get() + { + XCM_VERSION.saturating_sub(1).min(safe_xcm_version) + } else { + XCM_VERSION.saturating_sub(1) + }; + + // check `Queries` + ensure!( + !Queries::::iter_values() + .any(|data| data.needs_migration(minimal_allowed_xcm_version)), + TryRuntimeError::Other("`Queries` data should be migrated to the higher xcm version!") + ); + + // check `LockedFungibles` + ensure!( + !LockedFungibles::::iter_values() + .any(|data| data.needs_migration(minimal_allowed_xcm_version)), + TryRuntimeError::Other( + "`LockedFungibles` data should be migrated to the higher xcm version!" + ) + ); + + // check `RemoteLockedFungibles` + ensure!( + !RemoteLockedFungibles::::iter() + .any(|(key, data)| key.needs_migration(minimal_allowed_xcm_version) || + data.needs_migration(minimal_allowed_xcm_version)), + TryRuntimeError::Other( + "`RemoteLockedFungibles` data should be migrated to the higher xcm version!" + ) + ); + // if migration has been already scheduled, everything is ok and data will be eventually // migrated if CurrentMigration::::exists() { @@ -2792,7 +2926,7 @@ impl xcm_executor::traits::Enact for UnlockTicket { let mut maybe_remove_index = None; let mut locked = BalanceOf::::zero(); let mut found = false; - // We could just as well do with with an into_iter, filter_map and collect, however this way + // We could just as well do with an into_iter, filter_map and collect, however this way // avoids making an allocation. for (i, x) in locks.iter_mut().enumerate() { if x.1.try_as::<_>().defensive() == Ok(&self.unlocker) { @@ -2934,7 +3068,7 @@ impl xcm_executor::traits::AssetLock for Pallet { } impl WrapVersion for Pallet { - fn wrap_version( + fn wrap_version( dest: &Location, xcm: impl Into>, ) -> Result, ()> { @@ -2944,10 +3078,9 @@ impl WrapVersion for Pallet { SafeXcmVersion::::get() }) .ok_or_else(|| { - log::trace!( + tracing::trace!( target: "xcm::pallet_xcm::wrap_version", - "Could not determine a version to wrap XCM for destination: {:?}", - dest, + ?dest, "Could not determine a version to wrap XCM for destination", ); () }) @@ -3174,7 +3307,7 @@ impl OnResponse for Pallet { }); return Weight::zero() } - return match maybe_notify { + match maybe_notify { Some((pallet_index, call_index)) => { // This is a bit horrible, but we happen to know that the `Call` will // be built by `(pallet_index: u8, call_index: u8, QueryId, Response)`. @@ -3184,7 +3317,7 @@ impl OnResponse for Pallet { ::RuntimeCall::decode(&mut bytes) }) { Queries::::remove(query_id); - let weight = call.get_dispatch_info().weight; + let weight = call.get_dispatch_info().call_weight; if weight.any_gt(max_weight) { let e = Event::NotifyOverweight { query_id, diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index 0aec97ab4105..80154f57ddfb 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -15,7 +15,8 @@ // along with Polkadot. If not, see . use crate::{ - pallet::CurrentMigration, Config, Pallet, VersionMigrationStage, VersionNotifyTargets, + pallet::CurrentMigration, Config, CurrentXcmVersion, Pallet, VersionMigrationStage, + VersionNotifyTargets, }; use frame_support::{ pallet_prelude::*, @@ -25,6 +26,307 @@ use frame_support::{ const DEFAULT_PROOF_SIZE: u64 = 64 * 1024; +/// Utilities for handling XCM version migration for the relevant data. +pub mod data { + use crate::*; + + /// A trait for handling XCM versioned data migration for the requested `XcmVersion`. + pub(crate) trait NeedsMigration { + type MigratedData; + + /// Returns true if data does not match `minimal_allowed_xcm_version`. + fn needs_migration(&self, minimal_allowed_xcm_version: XcmVersion) -> bool; + + /// Attempts to migrate data. `Ok(None)` means no migration is needed. + /// `Ok(Some(Self::MigratedData))` should contain the migrated data. + fn try_migrate(self, to_xcm_version: XcmVersion) -> Result, ()>; + } + + /// Implementation of `NeedsMigration` for `LockedFungibles` data. + impl NeedsMigration for BoundedVec<(B, VersionedLocation), M> { + type MigratedData = Self; + + fn needs_migration(&self, minimal_allowed_xcm_version: XcmVersion) -> bool { + self.iter() + .any(|(_, unlocker)| unlocker.identify_version() < minimal_allowed_xcm_version) + } + + fn try_migrate( + mut self, + to_xcm_version: XcmVersion, + ) -> Result, ()> { + let mut was_modified = false; + for locked in self.iter_mut() { + if locked.1.identify_version() < to_xcm_version { + let Ok(new_unlocker) = locked.1.clone().into_version(to_xcm_version) else { + return Err(()) + }; + locked.1 = new_unlocker; + was_modified = true; + } + } + + if was_modified { + Ok(Some(self)) + } else { + Ok(None) + } + } + } + + /// Implementation of `NeedsMigration` for `Queries` data. + impl NeedsMigration for QueryStatus { + type MigratedData = Self; + + fn needs_migration(&self, minimal_allowed_xcm_version: XcmVersion) -> bool { + match &self { + QueryStatus::Pending { responder, maybe_match_querier, .. } => + responder.identify_version() < minimal_allowed_xcm_version || + maybe_match_querier + .as_ref() + .map(|v| v.identify_version() < minimal_allowed_xcm_version) + .unwrap_or(false), + QueryStatus::VersionNotifier { origin, .. } => + origin.identify_version() < minimal_allowed_xcm_version, + QueryStatus::Ready { response, .. } => + response.identify_version() < minimal_allowed_xcm_version, + } + } + + fn try_migrate(self, to_xcm_version: XcmVersion) -> Result, ()> { + if !self.needs_migration(to_xcm_version) { + return Ok(None) + } + + // do migration + match self { + QueryStatus::Pending { responder, maybe_match_querier, maybe_notify, timeout } => { + let Ok(responder) = responder.into_version(to_xcm_version) else { + return Err(()) + }; + let Ok(maybe_match_querier) = + maybe_match_querier.map(|mmq| mmq.into_version(to_xcm_version)).transpose() + else { + return Err(()) + }; + Ok(Some(QueryStatus::Pending { + responder, + maybe_match_querier, + maybe_notify, + timeout, + })) + }, + QueryStatus::VersionNotifier { origin, is_active } => origin + .into_version(to_xcm_version) + .map(|origin| Some(QueryStatus::VersionNotifier { origin, is_active })), + QueryStatus::Ready { response, at } => response + .into_version(to_xcm_version) + .map(|response| Some(QueryStatus::Ready { response, at })), + } + } + } + + /// Implementation of `NeedsMigration` for `RemoteLockedFungibles` key type. + impl NeedsMigration for (XcmVersion, A, VersionedAssetId) { + type MigratedData = Self; + + fn needs_migration(&self, minimal_allowed_xcm_version: XcmVersion) -> bool { + self.0 < minimal_allowed_xcm_version || + self.2.identify_version() < minimal_allowed_xcm_version + } + + fn try_migrate(self, to_xcm_version: XcmVersion) -> Result, ()> { + if !self.needs_migration(to_xcm_version) { + return Ok(None) + } + + let Ok(asset_id) = self.2.into_version(to_xcm_version) else { return Err(()) }; + Ok(Some((to_xcm_version, self.1, asset_id))) + } + } + + /// Implementation of `NeedsMigration` for `RemoteLockedFungibles` data. + impl> NeedsMigration + for RemoteLockedFungibleRecord + { + type MigratedData = Self; + + fn needs_migration(&self, minimal_allowed_xcm_version: XcmVersion) -> bool { + self.owner.identify_version() < minimal_allowed_xcm_version || + self.locker.identify_version() < minimal_allowed_xcm_version + } + + fn try_migrate(self, to_xcm_version: XcmVersion) -> Result, ()> { + if !self.needs_migration(to_xcm_version) { + return Ok(None) + } + + let RemoteLockedFungibleRecord { amount, owner, locker, consumers } = self; + + let Ok(owner) = owner.into_version(to_xcm_version) else { return Err(()) }; + let Ok(locker) = locker.into_version(to_xcm_version) else { return Err(()) }; + + Ok(Some(RemoteLockedFungibleRecord { amount, owner, locker, consumers })) + } + } + + impl Pallet { + /// Migrates relevant data to the `required_xcm_version`. + pub(crate) fn migrate_data_to_xcm_version( + weight: &mut Weight, + required_xcm_version: XcmVersion, + ) { + const LOG_TARGET: &str = "runtime::xcm::pallet_xcm::migrate_data_to_xcm_version"; + + // check and migrate `Queries` + let queries_to_migrate = Queries::::iter().filter_map(|(id, data)| { + weight.saturating_add(T::DbWeight::get().reads(1)); + match data.try_migrate(required_xcm_version) { + Ok(Some(new_data)) => Some((id, new_data)), + Ok(None) => None, + Err(_) => { + tracing::error!( + target: LOG_TARGET, + ?id, + ?required_xcm_version, + "`Queries` cannot be migrated!" + ); + None + }, + } + }); + for (id, new_data) in queries_to_migrate { + tracing::info!( + target: LOG_TARGET, + query_id = ?id, + ?new_data, + "Migrating `Queries`" + ); + Queries::::insert(id, new_data); + weight.saturating_add(T::DbWeight::get().writes(1)); + } + + // check and migrate `LockedFungibles` + let locked_fungibles_to_migrate = + LockedFungibles::::iter().filter_map(|(id, data)| { + weight.saturating_add(T::DbWeight::get().reads(1)); + match data.try_migrate(required_xcm_version) { + Ok(Some(new_data)) => Some((id, new_data)), + Ok(None) => None, + Err(_) => { + tracing::error!( + target: LOG_TARGET, + ?id, + ?required_xcm_version, + "`LockedFungibles` cannot be migrated!" + ); + None + }, + } + }); + for (id, new_data) in locked_fungibles_to_migrate { + tracing::info!( + target: LOG_TARGET, + account_id = ?id, + ?new_data, + "Migrating `LockedFungibles`" + ); + LockedFungibles::::insert(id, new_data); + weight.saturating_add(T::DbWeight::get().writes(1)); + } + + // check and migrate `RemoteLockedFungibles` - 1. step - just data + let remote_locked_fungibles_to_migrate = + RemoteLockedFungibles::::iter().filter_map(|(id, data)| { + weight.saturating_add(T::DbWeight::get().reads(1)); + match data.try_migrate(required_xcm_version) { + Ok(Some(new_data)) => Some((id, new_data)), + Ok(None) => None, + Err(_) => { + tracing::error!( + target: LOG_TARGET, + ?id, + ?required_xcm_version, + "`RemoteLockedFungibles` data cannot be migrated!" + ); + None + }, + } + }); + for (id, new_data) in remote_locked_fungibles_to_migrate { + tracing::info!( + target: LOG_TARGET, + key = ?id, + amount = ?new_data.amount, + locker = ?new_data.locker, + owner = ?new_data.owner, + consumers_count = ?new_data.consumers.len(), + "Migrating `RemoteLockedFungibles` data" + ); + RemoteLockedFungibles::::insert(id, new_data); + weight.saturating_add(T::DbWeight::get().writes(1)); + } + + // check and migrate `RemoteLockedFungibles` - 2. step - key + let remote_locked_fungibles_keys_to_migrate = RemoteLockedFungibles::::iter_keys() + .filter_map(|key| { + if key.needs_migration(required_xcm_version) { + let old_key = key.clone(); + match key.try_migrate(required_xcm_version) { + Ok(Some(new_key)) => Some((old_key, new_key)), + Ok(None) => None, + Err(_) => { + tracing::error!( + target: LOG_TARGET, + id = ?old_key, + ?required_xcm_version, + "`RemoteLockedFungibles` key cannot be migrated!" + ); + None + }, + } + } else { + None + } + }); + for (old_key, new_key) in remote_locked_fungibles_keys_to_migrate { + weight.saturating_add(T::DbWeight::get().reads(1)); + // make sure, that we don't override accidentally other data + if RemoteLockedFungibles::::get(&new_key).is_some() { + tracing::error!( + target: LOG_TARGET, + ?old_key, + ?new_key, + "`RemoteLockedFungibles` already contains data for a `new_key`!" + ); + // let's just skip for now, could be potentially caused with missing this + // migration before (manual clean-up?). + continue; + } + + tracing::info!( + target: LOG_TARGET, + ?old_key, + ?new_key, + "Migrating `RemoteLockedFungibles` key" + ); + + // now we can swap the keys + RemoteLockedFungibles::::swap::< + ( + NMapKey, + NMapKey, + NMapKey, + ), + _, + _, + >(&old_key, &new_key); + weight.saturating_add(T::DbWeight::get().writes(1)); + } + } + } +} + pub mod v1 { use super::*; use crate::{CurrentMigration, VersionMigrationStage}; @@ -40,7 +342,7 @@ pub mod v1 { let mut weight = T::DbWeight::get().reads(1); if StorageVersion::get::>() != 0 { - log::warn!("skipping v1, should be removed"); + tracing::warn!("skipping v1, should be removed"); return weight } @@ -50,13 +352,13 @@ pub mod v1 { let translate = |pre: (u64, u64, u32)| -> Option<(u64, Weight, u32)> { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); let translated = (pre.0, Weight::from_parts(pre.1, DEFAULT_PROOF_SIZE), pre.2); - log::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated); + tracing::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated); Some(translated) }; VersionNotifyTargets::::translate_values(translate); - log::info!("v1 applied successfully"); + tracing::info!("v1 applied successfully"); weight.saturating_accrue(T::DbWeight::get().writes(1)); StorageVersion::new(1).put::>(); weight @@ -84,7 +386,80 @@ pub mod v1 { pub struct MigrateToLatestXcmVersion(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToLatestXcmVersion { fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // trigger expensive/lazy migration (kind of multi-block) CurrentMigration::::put(VersionMigrationStage::default()); - T::DbWeight::get().writes(1) + weight.saturating_accrue(T::DbWeight::get().writes(1)); + + // migrate other operational data to the latest XCM version in-place + let latest = CurrentXcmVersion::get(); + Pallet::::migrate_data_to_xcm_version(&mut weight, latest); + + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_: alloc::vec::Vec) -> Result<(), sp_runtime::TryRuntimeError> { + use data::NeedsMigration; + const LOG_TARGET: &str = "runtime::xcm::pallet_xcm::migrate_to_latest"; + + let latest = CurrentXcmVersion::get(); + + let number_of_queries_to_migrate = crate::Queries::::iter() + .filter(|(id, data)| { + let needs_migration = data.needs_migration(latest); + if needs_migration { + tracing::warn!( + target: LOG_TARGET, + query_id = ?id, + query = ?data, + "Query was not migrated!" + ) + } + needs_migration + }) + .count(); + + let number_of_locked_fungibles_to_migrate = crate::LockedFungibles::::iter() + .filter_map(|(id, data)| { + if data.needs_migration(latest) { + tracing::warn!( + target: LOG_TARGET, + ?id, + ?data, + "LockedFungibles item was not migrated!" + ); + Some(true) + } else { + None + } + }) + .count(); + + let number_of_remote_locked_fungibles_to_migrate = + crate::RemoteLockedFungibles::::iter() + .filter_map(|(key, data)| { + if key.needs_migration(latest) || data.needs_migration(latest) { + tracing::warn!( + target: LOG_TARGET, + ?key, + "RemoteLockedFungibles item was not migrated!" + ); + Some(true) + } else { + None + } + }) + .count(); + + ensure!(number_of_queries_to_migrate == 0, "must migrate all `Queries`."); + ensure!(number_of_locked_fungibles_to_migrate == 0, "must migrate all `LockedFungibles`."); + ensure!( + number_of_remote_locked_fungibles_to_migrate == 0, + "must migrate all `RemoteLockedFungibles`." + ); + + Ok(()) } } diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index c16c1a1ba986..350530f7711f 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -19,11 +19,15 @@ pub(crate) mod assets_transfer; use crate::{ - mock::*, pallet::SupportedVersion, AssetTraps, Config, CurrentMigration, Error, - ExecuteControllerWeightInfo, LatestVersionedLocation, Pallet, Queries, QueryStatus, - RecordedXcm, ShouldRecordXcm, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, + migration::data::NeedsMigration, + mock::*, + pallet::{LockedFungibles, RemoteLockedFungibles, SupportedVersion}, + AssetTraps, Config, CurrentMigration, Error, ExecuteControllerWeightInfo, + LatestVersionedLocation, Pallet, Queries, QueryStatus, RecordedXcm, RemoteLockedFungibleRecord, + ShouldRecordXcm, VersionDiscoveryQueue, VersionMigrationStage, VersionNotifiers, VersionNotifyTargets, WeightInfo, }; +use bounded_collections::BoundedVec; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, traits::{Currency, Hooks}, @@ -478,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. @@ -508,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![]); @@ -1258,6 +1263,168 @@ fn multistage_migration_works() { }) } +#[test] +fn migrate_data_to_xcm_version_works() { + new_test_ext_with_balances(vec![]).execute_with(|| { + // check `try-state` + assert!(Pallet::::do_try_state().is_ok()); + + let latest_version = XCM_VERSION; + let previous_version = XCM_VERSION - 1; + + // `Queries` migration + { + let origin = VersionedLocation::from(Location::parent()); + let query_id1 = 0; + let query_id2 = 2; + let query_as_latest = + QueryStatus::VersionNotifier { origin: origin.clone(), is_active: true }; + let query_as_previous = QueryStatus::VersionNotifier { + origin: origin.into_version(previous_version).unwrap(), + is_active: true, + }; + assert_ne!(query_as_latest, query_as_previous); + assert!(!query_as_latest.needs_migration(latest_version)); + assert!(!query_as_latest.needs_migration(previous_version)); + assert!(query_as_previous.needs_migration(latest_version)); + assert!(!query_as_previous.needs_migration(previous_version)); + + // store two queries: migrated and not migrated + Queries::::insert(query_id1, query_as_latest.clone()); + Queries::::insert(query_id2, query_as_previous); + assert!(Pallet::::do_try_state().is_ok()); + + // trigger migration + Pallet::::migrate_data_to_xcm_version(&mut Weight::zero(), latest_version); + + // no change for query_id1 + assert_eq!(Queries::::get(query_id1), Some(query_as_latest.clone())); + // change for query_id2 + assert_eq!(Queries::::get(query_id2), Some(query_as_latest)); + assert!(Pallet::::do_try_state().is_ok()); + } + + // `LockedFungibles` migration + { + let account1 = AccountId::new([13u8; 32]); + let account2 = AccountId::new([58u8; 32]); + let unlocker = VersionedLocation::from(Location::parent()); + let lockeds_as_latest = BoundedVec::truncate_from(vec![(0, unlocker.clone())]); + let lockeds_as_previous = BoundedVec::truncate_from(vec![( + 0, + unlocker.into_version(previous_version).unwrap(), + )]); + assert_ne!(lockeds_as_latest, lockeds_as_previous); + assert!(!lockeds_as_latest.needs_migration(latest_version)); + assert!(!lockeds_as_latest.needs_migration(previous_version)); + assert!(lockeds_as_previous.needs_migration(latest_version)); + assert!(!lockeds_as_previous.needs_migration(previous_version)); + + // store two lockeds: migrated and not migrated + LockedFungibles::::insert(&account1, lockeds_as_latest.clone()); + LockedFungibles::::insert(&account2, lockeds_as_previous); + assert!(Pallet::::do_try_state().is_ok()); + + // trigger migration + Pallet::::migrate_data_to_xcm_version(&mut Weight::zero(), latest_version); + + // no change for account1 + assert_eq!(LockedFungibles::::get(&account1), Some(lockeds_as_latest.clone())); + // change for account2 + assert_eq!(LockedFungibles::::get(&account2), Some(lockeds_as_latest)); + assert!(Pallet::::do_try_state().is_ok()); + } + + // `RemoteLockedFungibles` migration + { + let account1 = AccountId::new([13u8; 32]); + let account2 = AccountId::new([58u8; 32]); + let account3 = AccountId::new([97u8; 32]); + let asset_id = VersionedAssetId::from(AssetId(Location::parent())); + let owner = VersionedLocation::from(Location::parent()); + let locker = VersionedLocation::from(Location::parent()); + let key1_as_latest = (latest_version, account1, asset_id.clone()); + let key2_as_latest = (latest_version, account2, asset_id.clone()); + let key3_as_previous = ( + previous_version, + account3.clone(), + asset_id.clone().into_version(previous_version).unwrap(), + ); + let expected_key3_as_latest = (latest_version, account3, asset_id); + let data_as_latest = RemoteLockedFungibleRecord { + amount: Default::default(), + owner: owner.clone(), + locker: locker.clone(), + consumers: Default::default(), + }; + let data_as_previous = RemoteLockedFungibleRecord { + amount: Default::default(), + owner: owner.into_version(previous_version).unwrap(), + locker: locker.into_version(previous_version).unwrap(), + consumers: Default::default(), + }; + assert_ne!(data_as_latest.owner, data_as_previous.owner); + assert_ne!(data_as_latest.locker, data_as_previous.locker); + assert!(!key1_as_latest.needs_migration(latest_version)); + assert!(!key1_as_latest.needs_migration(previous_version)); + assert!(!key2_as_latest.needs_migration(latest_version)); + assert!(!key2_as_latest.needs_migration(previous_version)); + assert!(key3_as_previous.needs_migration(latest_version)); + assert!(!key3_as_previous.needs_migration(previous_version)); + assert!(!expected_key3_as_latest.needs_migration(latest_version)); + assert!(!expected_key3_as_latest.needs_migration(previous_version)); + assert!(!data_as_latest.needs_migration(latest_version)); + assert!(!data_as_latest.needs_migration(previous_version)); + assert!(data_as_previous.needs_migration(latest_version)); + assert!(!data_as_previous.needs_migration(previous_version)); + + // store three lockeds: + // fully migrated + RemoteLockedFungibles::::insert(&key1_as_latest, data_as_latest.clone()); + // only key migrated + RemoteLockedFungibles::::insert(&key2_as_latest, data_as_previous.clone()); + // neither key nor data migrated + RemoteLockedFungibles::::insert(&key3_as_previous, data_as_previous); + assert!(Pallet::::do_try_state().is_ok()); + + // trigger migration + Pallet::::migrate_data_to_xcm_version(&mut Weight::zero(), latest_version); + + let assert_locked_eq = + |left: Option>, + right: Option>| { + match (left, right) { + (None, Some(_)) | (Some(_), None) => + assert!(false, "Received unexpected message"), + (None, None) => (), + (Some(l), Some(r)) => { + assert_eq!(l.owner, r.owner); + assert_eq!(l.locker, r.locker); + }, + } + }; + + // no change + assert_locked_eq( + RemoteLockedFungibles::::get(&key1_as_latest), + Some(data_as_latest.clone()), + ); + // change - data migrated + assert_locked_eq( + RemoteLockedFungibles::::get(&key2_as_latest), + Some(data_as_latest.clone()), + ); + // fully migrated + assert_locked_eq(RemoteLockedFungibles::::get(&key3_as_previous), None); + assert_locked_eq( + RemoteLockedFungibles::::get(&expected_key3_as_latest), + Some(data_as_latest.clone()), + ); + assert!(Pallet::::do_try_state().is_ok()); + } + }) +} + #[test] fn record_xcm_works() { let balances = vec![(ALICE, INITIAL_BALANCE)]; diff --git a/polkadot/xcm/procedural/src/builder_pattern.rs b/polkadot/xcm/procedural/src/builder_pattern.rs index 09ead1389d19..b65290332af9 100644 --- a/polkadot/xcm/procedural/src/builder_pattern.rs +++ b/polkadot/xcm/procedural/src/builder_pattern.rs @@ -160,13 +160,16 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result>>()?; @@ -260,50 +263,75 @@ fn generate_builder_impl(name: &Ident, data_enum: &DataEnum) -> Result, _>>()?; // 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, - } + .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 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) - }, - )?; + } + }, + _ => + return Err(Error::new_spanned( + variant, + "Both BuyExecution and PayFees have named fields", + )), + }; + Ok(fields) + }) + .collect::>>()?; let second_impl = quote! { impl XcmBuilder { #(#allowed_after_load_holding_methods)* - #buy_execution_method + #(#pay_fees_methods)* } }; diff --git a/polkadot/xcm/procedural/src/lib.rs b/polkadot/xcm/procedural/src/lib.rs index 4980d84d3282..9971fdceb69a 100644 --- a/polkadot/xcm/procedural/src/lib.rs +++ b/polkadot/xcm/procedural/src/lib.rs @@ -20,25 +20,11 @@ use proc_macro::TokenStream; use syn::{parse_macro_input, DeriveInput}; mod builder_pattern; -mod v2; 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 +58,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() 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/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/no_buy_execution.rs b/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs deleted file mode 100644 index 1ed8dd38cbad..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/no_buy_execution.rs +++ /dev/null @@ -1,29 +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 there's no `BuyExecution` instruction. - -use xcm_procedural::Builder; - -struct Xcm(pub Vec>); - -#[derive(Builder)] -enum Instruction { - UnpaidExecution { weight_limit: (u32, u32) }, - Transact { call: Call }, -} - -fn main() {} 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 deleted file mode 100644 index 1ff9d1851368..000000000000 --- a/polkadot/xcm/procedural/tests/ui/builder_pattern/unexpected_attribute.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Expected `builder(loads_holding)` - --> tests/ui/builder_pattern/unexpected_attribute.rs:25:5 - | -25 | #[builder(funds_holding)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ 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..1c8620708922 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 { 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..9baf58eacfb0 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,169 @@ 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 } => { + let require_weight_at_most = call.take_decoded()?.get_dispatch_info().call_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 { .. } | + SetAssetClaimer { .. } | + 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/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..952b61cd9ffe --- /dev/null +++ b/polkadot/xcm/src/v5/junction.rs @@ -0,0 +1,321 @@ +// 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. + Ethereum { + /// The EIP-155 chain ID. + #[codec(compact)] + chain_id: u64, + }, + /// The Bitcoin network, including hard-forks supported by Bitcoin Core development team. + BitcoinCore, + /// The Bitcoin network, including hard-forks supported by Bitcoin Cash developers. + BitcoinCash, + /// The Polkadot Bulletin chain. + 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..830b23cc44b7 --- /dev/null +++ b/polkadot/xcm/src/v5/mod.rs @@ -0,0 +1,1608 @@ +// 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, *}, + 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. + /// + /// Safety: No concerns. + /// + /// Kind: *Command*. + /// + /// Errors: + Transact { origin_kind: OriginKind, 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, + + /// 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. + /// + /// Kind: *Command* + /// + /// Errors: None. + SetAssetClaimer { location: Location }, + /// 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 }, +} + +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 } => Transact { origin_kind, call: call.into() }, + 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, + SetAssetClaimer { location } => SetAssetClaimer { location }, + 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, call } => W::transact(origin_kind, 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(), + SetAssetClaimer { location } => W::set_asset_claimer(location), + 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() }, + 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 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..1f5041ca8d84 --- /dev/null +++ b/polkadot/xcm/src/v5/traits.rs @@ -0,0 +1,525 @@ +// 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(), +/// }]); +/// 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; +} + +#[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) + } +} + +/// 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`. +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`. +/// +/// 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 671f0181277a..eaa115740f3e 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -49,6 +49,7 @@ runtime-benchmarks = [ "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-salary/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs index 4d9809e84f88..e6fe8e45c265 100644 --- a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs @@ -312,7 +312,7 @@ impl pallet_xcm::Config for Runtime { type UniversalLocation = UniversalLocation; // No version discovery needed const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 0; - type AdvertisedXcmVersion = frame_support::traits::ConstU32<3>; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type AdminOrigin = frame_system::EnsureRoot; // No locking type TrustedLockers = (); diff --git a/polkadot/xcm/xcm-builder/src/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index c995361ea8a3..56a8493ef0ab 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -108,6 +108,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/process_xcm_message.rs b/polkadot/xcm/xcm-builder/src/process_xcm_message.rs index 2e6f8c5fb566..8dafbf66adf0 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; @@ -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/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/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index 9f42aee87c9f..bec7b253977b 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -100,13 +100,13 @@ impl Dispatchable for TestCall { impl GetDispatchInfo for TestCall { fn get_dispatch_info(&self) -> DispatchInfo { - let weight = *match self { + let call_weight = *match self { TestCall::OnlyRoot(estimate, ..) | TestCall::OnlyParachain(estimate, ..) | TestCall::OnlySigned(estimate, ..) | TestCall::Any(estimate, ..) => estimate, }; - DispatchInfo { weight, ..Default::default() } + DispatchInfo { call_weight, ..Default::default() } } } diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 9f2146fa30e8..26ea226313f0 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -26,13 +26,21 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSigned}; use polkadot_primitives::{AccountIndex, BlakeTwo256, Signature}; -use polkadot_test_runtime::SignedExtra; use sp_runtime::{generic, traits::MaybeEquivalence, AccountId32, BuildStorage}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +pub type TxExtension = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckMortality, + frame_system::CheckNonce, + frame_system::CheckWeight, +); pub type Address = sp_runtime::MultiAddress; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Header = generic::Header; pub type Block = generic::Block; @@ -118,7 +126,6 @@ parameter_types! { pub const AnyNetwork: Option = None; pub UniversalLocation: InteriorLocation = (ByGenesis([0; 32]), Parachain(42)).into(); pub UnitWeightCost: u64 = 1_000; - pub static AdvertisedXcmVersion: u32 = 3; pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub CurrencyPerSecondPerByte: (AssetId, u128, u128) = (AssetId(RelayLocation::get()), 1, 1); pub TrustedAssets: (AssetFilter, Location) = (All.into(), Here.into()); @@ -259,7 +266,7 @@ impl pallet_xcm::Config for Test { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = AdvertisedXcmVersion; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type TrustedLockers = (); type SovereignAccountOf = SovereignAccountOf; type Currency = Balances; diff --git a/polkadot/xcm/xcm-builder/src/tests/transacting.rs b/polkadot/xcm/xcm-builder/src/tests/transacting.rs index a85c8b9986c8..8963e7147fdc 100644 --- a/polkadot/xcm/xcm-builder/src/tests/transacting.rs +++ b/polkadot/xcm/xcm-builder/src/tests/transacting.rs @@ -22,7 +22,6 @@ 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(), }]); let mut hash = fake_message_hash(&message); @@ -43,7 +42,6 @@ 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(), }]); let mut hash = fake_message_hash(&message); @@ -55,10 +53,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,7 +62,6 @@ 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(), @@ -98,7 +92,6 @@ 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() @@ -130,7 +123,6 @@ 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(), }, ReportTransactStatus(QueryResponseInfo { @@ -166,7 +158,6 @@ 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(), }, ReportTransactStatus(QueryResponseInfo { @@ -202,7 +193,6 @@ 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(), }, ExpectTransactStatus(MaybeErrorCode::Success), @@ -221,7 +211,6 @@ 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(), }, ExpectTransactStatus(MaybeErrorCode::Success), @@ -248,7 +237,6 @@ 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(), }, ExpectTransactStatus(vec![2].into()), @@ -267,7 +255,6 @@ 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(), }, ExpectTransactStatus(vec![2].into()), @@ -294,7 +281,6 @@ 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(), }, ClearTransactStatus, diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 30e0b7c72b03..5c754f01ec0a 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -337,15 +337,15 @@ impl InspectMessageQueues +impl InspectMessageQueues for SovereignPaidRemoteExporter { - fn clear_messages() { - Router::clear_messages() - } + fn clear_messages() {} + /// This router needs to implement `InspectMessageQueues` but doesn't have to + /// return any messages, since it just reuses the `XcmpQueue` router. fn get_messages() -> Vec<(VersionedLocation, Vec>)> { - Router::get_messages() + Vec::new() } } 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/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index 6f44cc0a75d5..9b918fd7eeed 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -17,14 +17,13 @@ #![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, }; use polkadot_test_runtime::{pallet_test_notifier, xcm_config::XcmConfig}; -use polkadot_test_service::{chain_spec::get_account_id_from_seed, construct_extrinsic}; -use sp_core::sr25519; +use polkadot_test_service::construct_extrinsic; use sp_runtime::traits::Block; use sp_state_machine::InspectState; use xcm::{latest::prelude::*, VersionedResponse, VersionedXcm}; @@ -80,11 +79,7 @@ fn transact_recursion_limit_works() { Xcm(vec![ WithdrawAsset((Here, 1_000).into()), BuyExecution { fees: (Here, 1).into(), weight_limit: Unlimited }, - Transact { - origin_kind: OriginKind::Native, - require_weight_at_most: call.get_dispatch_info().weight, - call: call.encode().into(), - }, + Transact { origin_kind: OriginKind::Native, call: call.encode().into() }, ]) }; let mut call: Option = None; @@ -242,7 +237,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() }), ) @@ -342,7 +337,7 @@ fn deposit_reserve_asset_works_for_any_xcm_sender() { let weight_limit = Unlimited; let reserve = Location::parent(); let dest = Location::new(1, [Parachain(2000)]); - let beneficiary_id = get_account_id_from_seed::("Alice"); + let beneficiary_id = sp_keyring::Sr25519Keyring::Alice.to_account_id(); let beneficiary = Location::new(0, [AccountId32 { network: None, id: beneficiary_id.into() }]); // spends up to half of fees for execution on reserve and other half for execution on diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index 14920f36445b..4e051f24050c 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,12 +531,12 @@ 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); // We withdraw or take from holding the asset the user wants to use for fee payment. - let withdrawn_fee_asset = if self.fees_mode.jit_withdraw { + let withdrawn_fee_asset: AssetsInHolding = if self.fees_mode.jit_withdraw { let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; Config::AssetTransactor::withdraw_asset( &asset_to_pay_for_fees, @@ -505,12 +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(|_| 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() }; @@ -518,15 +578,14 @@ impl XcmExecutor { let paid = if asset_to_pay_for_fees.id != asset_needed_for_fees.id { let swapped_asset: Assets = Config::AssetExchanger::exchange_asset( self.origin_ref(), - withdrawn_fee_asset, + withdrawn_fee_asset.clone().into(), &asset_needed_for_fees.clone().into(), false, ) .map_err(|given_assets| { tracing::error!( target: "xcm::fees", - ?given_assets, - "Swap was deemed necessary but couldn't be done", + ?given_assets, "Swap was deemed necessary but couldn't be done for withdrawn_fee_asset: {:?} and asset_needed_for_fees: {:?}", withdrawn_fee_asset.clone(), asset_needed_for_fees, ); XcmError::FeesNotMet })? @@ -542,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`. @@ -587,8 +650,10 @@ impl XcmExecutor { Ok(match local_querier { None => None, Some(q) => Some( - q.reanchored(&destination, &Config::UniversalLocation::get()) - .map_err(|_| XcmError::ReanchorFailed)?, + q.reanchored(&destination, &Config::UniversalLocation::get()).map_err(|e| { + tracing::error!(target: "xcm::xcm_executor::to_querier", ?e, ?destination, "Failed to re-anchor local_querier"); + XcmError::ReanchorFailed + })?, ), }) } @@ -610,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, @@ -617,7 +750,7 @@ impl XcmExecutor { let reanchor_context = Config::UniversalLocation::get(); let reanchored = reanchorable.reanchored(&destination, &reanchor_context).map_err(|error| { - tracing::error!(target: "xcm::reanchor", ?error, "Failed reanchoring with error"); + tracing::error!(target: "xcm::reanchor", ?error, ?destination, ?reanchor_context, "Failed reanchoring with error."); XcmError::ReanchorFailed })?; Ok((reanchored, reanchor_context)) @@ -634,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", @@ -648,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 @@ -684,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) }, } @@ -801,7 +939,7 @@ impl XcmExecutor { Ok(()) }) }, - Transact { origin_kind, require_weight_at_most, mut call } => { + 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!( @@ -857,19 +995,7 @@ impl XcmExecutor { "Dispatching with origin", ); - let weight = message_call.get_dispatch_info().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 weight = message_call.get_dispatch_info().call_weight; let maybe_actual_weight = match Config::CallDispatcher::dispatch(message_call, dispatch_origin) { Ok(post_info) => { @@ -894,9 +1020,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 @@ -917,16 +1041,25 @@ impl XcmExecutor { ); Ok(()) }, - DescendOrigin(who) => self - .context - .origin - .as_mut() - .ok_or(XcmError::BadOrigin)? - .append_with(who) - .map_err(|_| 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 @@ -943,7 +1076,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; @@ -953,42 +1086,28 @@ 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 - }); + let maybe_delivery_fee_from_holding = if self.fees.is_empty() { + self.get_delivery_fee_from_holding(&assets, &dest, &xcm)? + } else { + None + }; + + let mut message = Vec::with_capacity(xcm.len() + 2); // 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]; + Self::do_reserve_deposit_assets( + deposited, + &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_holding { + // 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)?; @@ -1003,18 +1122,16 @@ impl XcmExecutor { 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 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()); self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?; Ok(()) @@ -1026,37 +1143,131 @@ 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 result = Config::TransactionalProcessor::process(|| { 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 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()); 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 @@ -1083,21 +1294,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.into()).map_err(|_| XcmError::NotHoldingFees)?; - let result = || -> Result<(), XcmError> { + 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"); + XcmError::NotHoldingFees + })?; + 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) @@ -1119,6 +1370,10 @@ impl XcmExecutor { self.error = None; Ok(()) }, + SetAssetClaimer { 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())?; @@ -1150,7 +1405,10 @@ impl XcmExecutor { Ok(()) }, ExpectAsset(assets) => - self.holding.ensure_contains(&assets).map_err(|_| XcmError::ExpectationFalse), + self.holding.ensure_contains(&assets).map_err(|e| { + tracing::error!(target: "xcm::process_instruction::expect_asset", ?e, ?assets, "assets not contained in holding"); + XcmError::ExpectationFalse + }), ExpectOrigin(origin) => { ensure!(self.context.origin == origin, XcmError::ExpectationFalse); Ok(()) @@ -1272,9 +1530,10 @@ impl XcmExecutor { let (remote_asset, context) = Self::try_reanchor(asset.clone(), &unlocker)?; let lock_ticket = Config::AssetLocker::prepare_lock(unlocker.clone(), asset, origin.clone())?; - let owner = origin - .reanchored(&unlocker, &context) - .map_err(|_| XcmError::ReanchorFailed)?; + let owner = origin.reanchored(&unlocker, &context).map_err(|e| { + tracing::error!(target: "xcm::xcm_executor::process_instruction", ?e, ?unlocker, ?context, "Failed to re-anchor origin"); + XcmError::ReanchorFailed + })?; let msg = Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner }]); let (ticket, price) = validate_send::(unlocker, msg)?; self.take_fee(price, FeeReason::LockAsset)?; @@ -1324,7 +1583,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(), @@ -1338,7 +1597,7 @@ impl XcmExecutor { } else { Err(XcmError::NoDeal) } - })(); + }); if result.is_err() { self.holding = old_holding; } @@ -1390,6 +1649,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. @@ -1400,16 +1676,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); @@ -1427,8 +1702,43 @@ 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(()) } + + /// Gets the necessary delivery fee to send a reserve transfer message to `destination` from + /// holding. + /// + /// Will be removed once the transition from `BuyExecution` to `PayFees` is complete. + fn get_delivery_fee_from_holding( + &mut self, + assets: &AssetFilter, + destination: &Location, + xcm: &Xcm<()>, + ) -> Result, XcmError> { + // 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, &destination, 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::(destination.clone(), Xcm(message_to_weigh))?; + let maybe_delivery_fee = fee.get(0).map(|asset_needed_for_fees| { + tracing::trace!( + target: "xcm::fees::DepositReserveAsset", + "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 = self.holding.saturating_take(asset_to_pay_for_fees.into()); + tracing::trace!(target: "xcm::fees::DepositReserveAsset", ?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..bc504b8db2a2 --- /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_asset_claimer(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_asset_claimer(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_asset_claimer(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/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/src/lib.rs b/polkadot/xcm/xcm-runtime-apis/src/lib.rs index 44e518e8e7ab..f9a857c7c4ce 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/lib.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/lib.rs @@ -30,3 +30,7 @@ pub mod dry_run; /// Fee estimation API. /// Given an XCM program, it will return the fees needed to execute it properly or send it. pub mod fees; + +// Exposes runtime API for querying whether a Location is trusted as a reserve or teleporter for a +// given Asset. +pub mod trusted_query; diff --git a/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs b/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs new file mode 100644 index 000000000000..a2e3e1625486 --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs @@ -0,0 +1,50 @@ +// 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 . + +//! Runtime API definition for checking if given is trusted reserve or teleporter. + +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::TypeInfo; +use xcm::{VersionedAsset, VersionedLocation}; + +/// Result of [`TrustedQueryApi`] functions. +pub type XcmTrustedQueryResult = Result; + +sp_api::decl_runtime_apis! { + // API for querying trusted reserves and trusted teleporters. + pub trait TrustedQueryApi { + /// Returns if the location is a trusted reserve for the asset. + /// + /// # Arguments + /// * `asset`: `VersionedAsset`. + /// * `location`: `VersionedLocation`. + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> XcmTrustedQueryResult; + /// Returns if the asset can be teleported to the location. + /// + /// # Arguments + /// * `asset`: `VersionedAsset`. + /// * `location`: `VersionedLocation`. + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> XcmTrustedQueryResult; + } +} + +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// Converting a versioned Asset structure from one version to another failed. + VersionedAssetConversionFailed, + /// Converting a versioned Location structure from one version to another failed. + VersionedLocationConversionFailed, +} diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 6575feccf8a3..f0a5be908f69 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -48,6 +48,7 @@ use xcm_runtime_apis::{ conversions::{Error as LocationToAccountApiError, LocationToAccountApi}, dry_run::{CallDryRunEffects, DryRunApi, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::{Error as XcmPaymentApiError, XcmPaymentApi}, + trusted_query::{Error as TrustedQueryApiError, TrustedQueryApi}, }; construct_runtime! { @@ -59,9 +60,16 @@ construct_runtime! { } } -pub type SignedExtra = (frame_system::CheckWeight,); -pub type TestXt = sp_runtime::testing::TestXt; -type Block = sp_runtime::testing::Block; +pub type TxExtension = (frame_system::CheckWeight,); + +// we only use the hash type from this, so using the mock should be fine. +pub(crate) type Extrinsic = sp_runtime::generic::UncheckedExtrinsic< + u64, + RuntimeCall, + sp_runtime::testing::UintAuthorityId, + TxExtension, +>; +type Block = sp_runtime::testing::Block; type Balance = u128; type AssetIdForAssetsPallet = u32; type AccountId = u64; @@ -136,8 +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 static AdvertisedXcmVersion: XcmVersion = 4; + 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; @@ -341,7 +348,7 @@ impl pallet_xcm::Config for TestRuntime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = AdvertisedXcmVersion; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type AdminOrigin = EnsureRoot; type TrustedLockers = (); type SovereignAccountOf = (); @@ -414,6 +421,16 @@ impl sp_api::ProvideRuntimeApi for TestClient { } sp_api::mock_impl_runtime_apis! { + impl TrustedQueryApi for RuntimeApi { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_reserve(asset, location) + } + + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_teleporter(asset, location) + } + } + impl LocationToAccountApi for RuntimeApi { fn convert_location(location: VersionedLocation) -> Result { let location = location.try_into().map_err(|_| LocationToAccountApiError::VersionedConversionFailed)?; diff --git a/polkadot/xcm/xcm-runtime-apis/tests/trusted_query.rs b/polkadot/xcm/xcm-runtime-apis/tests/trusted_query.rs new file mode 100644 index 000000000000..5e3a68b9225b --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/tests/trusted_query.rs @@ -0,0 +1,150 @@ +// 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 . + +mod mock; + +use frame_support::sp_runtime::testing::H256; +use mock::*; +use sp_api::ProvideRuntimeApi; +use xcm::{prelude::*, v3}; +use xcm_runtime_apis::trusted_query::{Error, TrustedQueryApi}; + +#[test] +fn query_trusted_reserve() { + #[derive(Debug)] + struct TestCase { + name: &'static str, + asset: VersionedAsset, + location: VersionedLocation, + expected: Result, + } + + sp_io::TestExternalities::default().execute_with(|| { + let client = TestClient {}; + let runtime_api = client.runtime_api(); + + let test_cases: Vec = vec![ + TestCase { + // matches!(asset.id.0.unpack(), (1, [])) && matches!(origin.unpack(), (1, + // [Parachain(1000)])) + name: "Valid asset and location", + asset: Asset { id: AssetId(Location::parent()), fun: Fungible(123) }.into(), + location: (Parent, Parachain(1000)).into(), + expected: Ok(true), + }, + TestCase { + name: "Invalid location and valid asset", + asset: Asset { id: AssetId(Location::parent()), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1002)).into(), + expected: Ok(false), + }, + TestCase { + name: "Valid location and invalid asset", + asset: Asset { id: AssetId(Location::new(0, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1000)).into(), + expected: Ok(false), + }, + TestCase { + name: "Invalid asset conversion", + asset: VersionedAsset::V3(v3::MultiAsset { + id: v3::AssetId::Abstract([1; 32]), + fun: v3::Fungibility::Fungible(1), + }), + location: (Parent, Parachain(1000)).into(), + expected: Err(Error::VersionedAssetConversionFailed), + }, + ]; + + for tc in test_cases { + let res = + runtime_api.is_trusted_reserve(H256::zero(), tc.asset.clone(), tc.location.clone()); + let inner_res = res.unwrap_or_else(|e| { + panic!("Test case '{}' failed with ApiError: {:?}", tc.name, e); + }); + + assert_eq!( + tc.expected, inner_res, + "Test case '{}' failed: expected {:?}, got {:?}", + tc.name, tc.expected, inner_res + ); + } + }); +} + +#[test] +fn query_trusted_teleporter() { + #[derive(Debug)] + struct TestCase { + name: &'static str, + asset: VersionedAsset, + location: VersionedLocation, + expected: Result, + } + + sp_io::TestExternalities::default().execute_with(|| { + let client = TestClient {}; + let runtime_api = client.runtime_api(); + + let test_cases: Vec = vec![ + TestCase { + // matches!(asset.id.0.unpack(), (0, [])) && matches!(origin.unpack(), (1, + // [Parachain(1000)])) + name: "Valid asset and location", + asset: Asset { id: AssetId(Location::new(0, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1000)).into(), + expected: Ok(true), + }, + TestCase { + name: "Invalid location and valid asset", + asset: Asset { id: AssetId(Location::new(0, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1002)).into(), + expected: Ok(false), + }, + TestCase { + name: "Valid location and invalid asset", + asset: Asset { id: AssetId(Location::new(1, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1002)).into(), + expected: Ok(false), + }, + TestCase { + name: "Invalid asset conversion", + asset: VersionedAsset::V3(v3::MultiAsset { + id: v3::AssetId::Abstract([1; 32]), + fun: v3::Fungibility::Fungible(1), + }), + location: (Parent, Parachain(1000)).into(), + expected: Err(Error::VersionedAssetConversionFailed), + }, + ]; + + for tc in test_cases { + let res = runtime_api.is_trusted_teleporter( + H256::zero(), + tc.asset.clone(), + tc.location.clone(), + ); + let inner_res = res.unwrap_or_else(|e| { + panic!("Test case '{}' failed with ApiError: {:?}", tc.name, e); + }); + + assert_eq!( + tc.expected, inner_res, + "Test case '{}' failed: expected {:?}, got {:?}", + tc.name, tc.expected, inner_res + ); + } + }); +} diff --git a/polkadot/xcm/xcm-simulator/example/src/tests.rs b/polkadot/xcm/xcm-simulator/example/src/tests.rs index 34c1feb6e946..bbac44ed8a1f 100644 --- a/polkadot/xcm/xcm-simulator/example/src/tests.rs +++ b/polkadot/xcm/xcm-simulator/example/src/tests.rs @@ -46,7 +46,6 @@ 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(), }]), )); @@ -74,7 +73,6 @@ 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(), }]), )); @@ -102,7 +100,6 @@ 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(), }]), )); @@ -383,7 +380,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(), diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 616329a2f06b..fc650ae55a78 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -44,13 +44,13 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -pub type SignedExtra = (frame_system::CheckNonZeroSender,); +pub type TxExtension = (frame_system::CheckNonZeroSender,); pub type BlockNumber = u64; pub type Address = MultiAddress; pub type Header = generic::Header; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Block = generic::Block; pub type Signature = MultiSignature; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 459d2640b6d9..58687b478526 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -45,13 +45,13 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -pub type SignedExtra = (frame_system::CheckNonZeroSender,); +pub type TxExtension = (frame_system::CheckNonZeroSender,); pub type BlockNumber = u64; pub type Address = MultiAddress; pub type Header = generic::Header; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Block = generic::Block; pub type Signature = MultiSignature; diff --git a/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl b/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl index 8300ef051f09..4fc066a13b07 100644 --- a/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl +++ b/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl @@ -18,22 +18,22 @@ validator-unstable: reports substrate_beefy_best_block is at least 1 within 60 s validator-unstable: pause # Verify validator sets get changed on new sessions. -validator: reports substrate_beefy_validator_set_id is at least 1 within 70 seconds +validator: reports substrate_beefy_validator_set_id is at least 1 within 180 seconds # Check next session too. -validator: reports substrate_beefy_validator_set_id is at least 2 within 130 seconds +validator: reports substrate_beefy_validator_set_id is at least 2 within 180 seconds # Verify voting happens and blocks are being finalized for new sessions too: # since we verified we're at least in the 3rd session, verify BEEFY finalized mandatory #21. -validator: reports substrate_beefy_best_block is at least 21 within 130 seconds +validator: reports substrate_beefy_best_block is at least 21 within 180 seconds # Custom JS to test BEEFY RPCs. -validator-0: js-script ./0003-beefy-finalized-heads.js with "validator-0,validator-1,validator-2" return is 1 within 5 seconds +validator-0: js-script ./0003-beefy-finalized-heads.js with "validator-0,validator-1,validator-2" return is 1 within 60 seconds # Custom JS to test MMR RPCs. -validator: js-script ./0003-mmr-leaves.js with "21" return is 1 within 5 seconds -validator: js-script ./0003-mmr-generate-and-verify-proof.js with "validator-0,validator-1,validator-2" return is 1 within 5 seconds +validator: js-script ./0003-mmr-leaves.js with "21" return is 1 within 60 seconds +validator: js-script ./0003-mmr-generate-and-verify-proof.js with "validator-0,validator-1,validator-2" return is 1 within 60 seconds # Resume validator-unstable and verify it imports all BEEFY justification and catches up. validator-unstable: resume -validator-unstable: reports substrate_beefy_validator_set_id is at least 2 within 30 seconds -validator-unstable: reports substrate_beefy_best_block is at least 21 within 30 seconds +validator-unstable: reports substrate_beefy_validator_set_id is at least 2 within 60 seconds +validator-unstable: reports substrate_beefy_best_block is at least 21 within 60 seconds diff --git a/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl b/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl index b8b8887df857..8f883dffa5e1 100644 --- a/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl +++ b/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl @@ -5,8 +5,8 @@ Creds: config validator: reports node_roles is 4 # register paras 2 by 2 to speed up the test. registering all at once will exceed the weight limit. -validator-0: js-script ./0015-force-register-paras.js with "2000,2001" return is 0 within 600 seconds -validator-0: js-script ./0015-force-register-paras.js with "2002,2003" return is 0 within 600 seconds +validator-0: js-script ./force-register-paras.js with "2000,2001" return is 0 within 600 seconds +validator-0: js-script ./force-register-paras.js with "2002,2003" return is 0 within 600 seconds # assign core 0 to be shared by all paras. validator-0: js-script ./assign-core.js with "0,2000,14400,2001,14400,2002,14400,2003,14400" return is 0 within 600 seconds diff --git a/polkadot/zombienet_tests/functional/0017-sync-backing.toml b/polkadot/zombienet_tests/functional/0017-sync-backing.toml new file mode 100644 index 000000000000..2550054c8dad --- /dev/null +++ b/polkadot/zombienet_tests/functional/0017-sync-backing.toml @@ -0,0 +1,48 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] + max_candidate_depth = 0 + allowed_ancestry_len = 0 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + lookahead = 2 + group_rotation_frequency = 4 + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "alice" + args = [ "-lparachain=debug" ] + count = 10 + +[[parachains]] +id = 2000 +addToGenesis = true + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "adder-collator" + args = ["-lparachain=debug"] + +[[parachains]] +id = 2001 +cumulus_based = true + + [parachains.collator] + name = "collator02" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" \ No newline at end of file diff --git a/polkadot/zombienet_tests/functional/0017-sync-backing.zndsl b/polkadot/zombienet_tests/functional/0017-sync-backing.zndsl new file mode 100644 index 000000000000..a53de784b2d1 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0017-sync-backing.zndsl @@ -0,0 +1,22 @@ +Description: Test we are producing 12-second parachain blocks if sync backing is configured +Network: ./0017-sync-backing.toml +Creds: config + +# Check authority status. +alice: reports node_roles is 4 + +# Ensure parachains are registered. +alice: parachain 2000 is registered within 60 seconds +alice: parachain 2001 is registered within 60 seconds + +# Ensure parachains made progress. +alice: reports substrate_block_height{status="finalized"} is at least 10 within 100 seconds + +# This parachains should produce blocks at 12s clip, let's assume an 14s rate, allowing for +# some slots to be missed on slower machines +alice: parachain 2000 block height is at least 21 within 300 seconds +alice: parachain 2000 block height is lower than 25 within 2 seconds + +# This should already have produced the needed blocks +alice: parachain 2001 block height is at least 21 within 10 seconds +alice: parachain 2001 block height is lower than 25 within 2 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 new file mode 100644 index 000000000000..745c4f9e24b1 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml @@ -0,0 +1,39 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 2 + lookahead = 2 + num_cores = 4 + group_rotation_frequency = 4 + + +[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 = ["-lruntime=debug,parachain=debug"] + 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"] diff --git a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl new file mode 100644 index 000000000000..dce52505444e --- /dev/null +++ b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl @@ -0,0 +1,11 @@ +Description: Test that a parachain can keep producing blocks even if the other parachain with which it's sharing a core doesn't +Network: ./0018-shared-core-idle-parachain.toml +Creds: config + +validator: reports node_roles is 4 + +validator-0: js-script ./force-register-paras.js with "2000" return is 0 within 600 seconds +# 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 210 seconds diff --git a/polkadot/zombienet_tests/functional/0015-force-register-paras.js b/polkadot/zombienet_tests/functional/force-register-paras.js similarity index 100% rename from polkadot/zombienet_tests/functional/0015-force-register-paras.js rename to polkadot/zombienet_tests/functional/force-register-paras.js diff --git a/polkadot/zombienet_tests/smoke/0004-coretime-smoke-test.zndsl b/polkadot/zombienet_tests/smoke/0004-coretime-smoke-test.zndsl index cfb1ce7d9821..9852d5fc5802 100644 --- a/polkadot/zombienet_tests/smoke/0004-coretime-smoke-test.zndsl +++ b/polkadot/zombienet_tests/smoke/0004-coretime-smoke-test.zndsl @@ -8,6 +8,9 @@ coretime-collator: is up # configure relay chain alice: js-script ./0004-configure-relay.js with "" return is 0 within 600 secs +# Coretime chain should be producing blocks when the extrinsic is sent +alice: parachain 1005 block height is at least 10 within 180 seconds + # configure broker chain coretime-collator: js-script ./0004-configure-broker.js with "" return is 0 within 600 secs diff --git a/prdoc/1.16.1/pr_4803.prdoc b/prdoc/1.16.1/pr_4803.prdoc new file mode 100644 index 000000000000..0d2ad08d610f --- /dev/null +++ b/prdoc/1.16.1/pr_4803.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: Fix for issue #4762 + +doc: + - audience: Runtime Dev + description: | + When the status of the queue is on_initialize, throw a defensive message and return weight of 0, + however when status is on_idle, do not throw a defensive message, only return weight of 0 + +crates: + - name: pallet-message-queue + bump: patch diff --git a/prdoc/1.16.1/pr_5599.prdoc b/prdoc/1.16.1/pr_5599.prdoc new file mode 100644 index 000000000000..990d2bb4e18f --- /dev/null +++ b/prdoc/1.16.1/pr_5599.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: Add assets in pool with native to query_acceptable_payment_assets + +doc: + - audience: Runtime Dev + description: | + The `XcmPaymentApi::query_acceptable_payment_assets` API can be used to get a list of all + the assets that can be used for fee payment. + This is usually just the native asset, but the asset hubs have the asset conversion pallet. + In the case of the asset hubs, this list now includes all assets in a liquidity pool with + the native one. + +crates: + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor diff --git a/prdoc/pr_5753.prdoc b/prdoc/1.16.1/pr_5753.prdoc similarity index 100% rename from prdoc/pr_5753.prdoc rename to prdoc/1.16.1/pr_5753.prdoc diff --git a/prdoc/pr_5887.prdoc b/prdoc/1.16.1/pr_5887.prdoc similarity index 100% rename from prdoc/pr_5887.prdoc rename to prdoc/1.16.1/pr_5887.prdoc diff --git a/prdoc/1.16.1/pr_5913.prdoc b/prdoc/1.16.1/pr_5913.prdoc new file mode 100644 index 000000000000..f50cd722c714 --- /dev/null +++ b/prdoc/1.16.1/pr_5913.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: Remove redundant XCMs from dry run's forwarded xcms + +doc: + - audience: Runtime User + description: | + The DryRunApi was returning the same message repeated multiple times in the + `forwarded_xcms` field. This is no longer the case. + +crates: + - name: pallet-xcm-bridge-hub-router + bump: patch + - name: cumulus-pallet-parachain-system + bump: patch + - name: staging-xcm-builder + bump: patch + - name: emulated-integration-tests-common + bump: minor diff --git a/prdoc/1.16.1/pr_6031.prdoc b/prdoc/1.16.1/pr_6031.prdoc new file mode 100644 index 000000000000..702d0c12fa06 --- /dev/null +++ b/prdoc/1.16.1/pr_6031.prdoc @@ -0,0 +1,10 @@ +title: "Import vec to bridges/primitives/header-chain" + +doc: + - audience: Runtime Dev + description: | + Add the `vec` dependency to these files to resolve compiler errors. + +crates: + - name: bp-header-chain + bump: patch diff --git a/prdoc/pr_3685.prdoc b/prdoc/pr_3685.prdoc new file mode 100644 index 000000000000..bd414c93a6fe --- /dev/null +++ b/prdoc/pr_3685.prdoc @@ -0,0 +1,300 @@ +# 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: FRAME Reintroduce `TransactionExtension` as a replacement for `SignedExtension` + +doc: + - audience: [Runtime Dev, Runtime User, Node Operator, Node Dev] + description: | + Introduces a new trait `TransactionExtension` to replace `SignedExtension`. Introduce the + idea of transactions which obey the runtime's extensions and have according Extension data + (né Extra data) yet do not have hard-coded signatures. + + Deprecate the terminology of "Unsigned" when used for transactions/extrinsics owing to there + now being "proper" unsigned transactions which obey the extension framework and "old-style" + unsigned which do not. Instead we have `General` for the former and `Bare` for the latter. + Unsigned will be phased out as a type of transaction, and `Bare` will only be used for + Inherents. + + Types of extrinsic are now therefore + - Bare (no hardcoded signature, no Extra data; used to be known as "Unsigned") + - Bare transactions (deprecated) - Gossiped, validated with `ValidateUnsigned` + (deprecated) and the `_bare_compat` bits of `TransactionExtension` (deprecated). + - Inherents - Not gossiped, validated with `ProvideInherent`. + - Extended (Extra data) - Gossiped, validated via `TransactionExtension`. + - Signed transactions (with a hardcoded signature). + - General transactions (without a hardcoded signature). + + Notable information on `TransactionExtension` and the differences from `SignedExtension` + - `AdditionalSigned`/`additional_signed` is renamed to `Implicit`/`implicit`. It is encoded + for the entire transaction and passed in to each extension as a new argument to validate. + - `pre_dispatch` is renamed to `prepare`. + - `validate` runs transaction validation logic both off-chain and on-chain, and is + non-mutating. + - `prepare` runs on-chain pre-execution logic using information extracted during validation + and is mutating. + - `validate` and `prepare` are now passed an `Origin` rather than an `AccountId`. If the + extension logic presumes an `AccountId`, consider using the trait function + `AsSystemOriginSigner::as_system_origin_signer`. + - A signature on the underlying transaction may validly not be present. + - The origin may be altered during validation. + - Validation functionality present in `validate` should not be repeated in `prepare`. + Useful information obtained during `validate` should now be passed in to `prepare` using + the new user-specifiable type `Val`. + - Unsigned logic should be temporarily migrated from the old `*_unsigned` functions into the + regular versions of the new functions where the `Origin` is `None`, until the deprecation + of `ValidateUnsigned` in phase 2 of Extrinsic Horizon. + - The `Call` type defining the runtime call is now a type parameter. + - Extensions now track the weight they consume during validation, preparation and + post-dispatch through the `TransactionExtensionBase::weight` function. + - `TestXt` was removed and its usage in tests was replaced with `UncheckedExtrinsic` + instances. + + To fix the build issues introduced by this change, use the `AsTransactionExtension` adapter + to wrap existing `SignedExtension`s by converting them using the `From` + generic implementation for `AsTransactionExtension`. More details on migrating existing + `SignedExtension` implementations to `TransactionExtension` in the PR description. + +crates: + - name: bridge-runtime-common + bump: major + - name: bp-bridge-hub-cumulus + bump: major + - name: bp-bridge-hub-rococo + bump: major + - name: bp-bridge-hub-westend + bump: major + - name: bp-kusama + bump: major + - name: bp-polkadot-bulletin + bump: major + - name: bp-polkadot + bump: major + - name: bp-rococo + bump: major + - name: bp-westend + bump: major + - name: pallet-bridge-relayers + bump: major + - name: bp-polkadot-core + bump: major + - name: bp-relayers + bump: major + - name: bp-runtime + bump: major + - name: substrate-relay-helper + bump: major + - name: snowbridge-pallet-ethereum-client + bump: major + - name: snowbridge-pallet-inbound-queue + bump: major + - name: snowbridge-pallet-outbound-queue + bump: major + - name: snowbridge-pallet-system + bump: major + - name: snowbridge-runtime-test-common + bump: major + - name: parachain-template-runtime + 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: parachains-runtimes-test-utils + bump: major + - name: penpal-runtime + bump: major + - name: rococo-parachain-runtime + bump: major + - name: polkadot-omni-node + bump: major + - name: polkadot-parachain-bin + bump: major + - name: cumulus-primitives-storage-weight-reclaim + bump: major + - name: cumulus-test-client + bump: major + - name: cumulus-test-runtime + bump: major + - name: cumulus-test-service + bump: major + - name: polkadot-sdk-docs + bump: major + - name: polkadot-service + bump: major + - name: polkadot-test-service + bump: major + - name: polkadot-runtime-common + bump: major + - name: polkadot-runtime-parachains + bump: major + - name: rococo-runtime + bump: major + - name: polkadot-test-runtime + bump: major + - name: westend-runtime + bump: major + - name: pallet-xcm-benchmarks + bump: major + - name: pallet-xcm + bump: major + - name: staging-xcm-builder + bump: major + - name: staging-xcm-executor + bump: major + - name: xcm-runtime-apis + bump: major + - name: xcm-simulator + bump: major + - name: minimal-template-runtime + bump: major + - name: minimal-template-node + bump: major + - name: solochain-template-runtime + bump: major + - name: staging-node-cli + bump: major + - name: kitchensink-runtime + bump: major + - name: node-testing + bump: major + - name: sc-client-api + bump: major + - name: sc-client-db + bump: major + - name: sc-network-gossip + bump: major + - name: sc-network-sync + bump: major + - name: sc-transaction-pool + bump: major + - name: polkadot-sdk-frame + bump: major + - name: pallet-alliance + bump: major + - name: pallet-assets + bump: major + - name: pallet-asset-conversion + bump: major + - name: pallet-babe + bump: major + - name: pallet-balances + bump: major + - name: pallet-beefy + bump: major + - name: pallet-collective + bump: major + - name: pallet-contracts + bump: major + - name: pallet-election-provider-multi-phase + bump: major + - name: pallet-elections-phragmen + bump: major + - name: pallet-example-basic + bump: major + - name: pallet-example-tasks + bump: major + - name: pallet-example-offchain-worker + bump: major + - name: pallet-examples + bump: major + - name: frame-executive + bump: major + - name: pallet-grandpa + bump: major + - name: pallet-im-online + bump: major + - name: pallet-lottery + bump: major + - name: frame-metadata-hash-extension + bump: major + - name: pallet-mixnet + bump: major + - name: pallet-multisig + bump: major + - name: pallet-offences + bump: major + - name: pallet-proxy + bump: major + - name: pallet-recovery + bump: major + - name: pallet-revive + bump: major + - name: pallet-sassafras + bump: major + - name: pallet-scheduler + bump: major + - name: pallet-state-trie-migration + bump: major + - name: pallet-sudo + bump: major + - name: frame-support-procedural + bump: major + - name: frame-support + bump: major + - name: frame-support-test + bump: major + - name: frame-system + bump: major + - name: frame-system-benchmarking + bump: major + - name: pallet-transaction-payment + bump: major + - name: pallet-asset-conversion-tx-payment + bump: major + - name: pallet-asset-tx-payment + bump: major + - name: pallet-skip-feeless-payment + bump: major + - name: pallet-utility + bump: major + - name: pallet-whitelist + bump: major + - name: sp-inherents + bump: major + - name: sp-metadata-ir + bump: major + - name: sp-runtime + bump: major + - name: sp-storage + bump: major + - name: sp-test-primitives + bump: major + - name: substrate-test-runtime + bump: major + - name: substrate-test-utils + bump: major + - name: frame-benchmarking-cli + bump: major + - name: frame-remote-externalities + bump: major + - name: substrate-rpc-client + bump: major + - name: minimal-template-runtime + bump: major + - name: parachain-template-runtime + bump: major + - name: solochain-template-node + bump: major + - name: polkadot-sdk + bump: major diff --git a/prdoc/pr_3970.prdoc b/prdoc/pr_3970.prdoc new file mode 100644 index 000000000000..5c20e7444782 --- /dev/null +++ b/prdoc/pr_3970.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: Update Treasury to Support Block Number Provider + +doc: + - audience: Runtime Dev + description: | + The goal of this PR is to have the treasury pallet work on a parachain which does not produce blocks on a regular schedule, thus can use the relay chain as a block provider. Because blocks are not produced regularly, we cannot make the assumption that block number increases monotonically, and thus have new logic to handle multiple spend periods passing between blocks. To migrate existing treasury implementations, simply add `type BlockNumberProvider = System` to have the same behavior as before. + +crates: +- name: pallet-treasury + bump: major +- name: pallet-bounties + bump: minor +- name: pallet-child-bounties + bump: minor diff --git a/prdoc/pr_4012.prdoc b/prdoc/pr_4012.prdoc new file mode 100644 index 000000000000..3a53e31a7fc6 --- /dev/null +++ b/prdoc/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_4639.prdoc b/prdoc/pr_4639.prdoc new file mode 100644 index 000000000000..dfdd60f2bdb2 --- /dev/null +++ b/prdoc/pr_4639.prdoc @@ -0,0 +1,69 @@ +title: "Added the fork-aware transaction pool implementation" + +doc: + - audience: Node Dev + description: | + Most important changes introduced by this PR: + - The transaction pool references spread across codebase are now wrapper to a transaction pool trait object, + - The fork-aware pool implementation was added. + - The `sc-transaction-pool` refactored, + - Trasnaction pool builder was introduced to allow to instantiation of either old or new transaction pool. Refer to PR description for + more details on how to enable fork-aware pool in the custom node. + - audience: Node Operator + description: | + - New command line option was added, allowing to select implementation of transaction pool: + - `--pool-type=fork-aware` - new fork aware transaction pool, + - `--pool-type=single-state` - old transaction pool implementation which is still default, + +crates: + - name: sc-basic-authorship + bump: patch + - name: sc-cli + bump: major + - name: sc-consensus-manual-seal + bump: patch + - name: sc-network-transactions + bump: none + - name: sc-rpc + bump: patch + - name: sc-rpc-spec-v2 + bump: patch + - name: sc-offchain + bump: patch + - name: sc-service + bump: patch + - name: sc-service-test + bump: minor + - name: sc-transaction-pool + bump: major + - name: sc-transaction-pool-api + bump: major + validate: false + - name: sp-runtime + bump: patch + - name: substrate-test-runtime-transaction-pool + bump: minor + - name: staging-node-cli + bump: minor + - name: node-bench + bump: patch + - name: node-rpc + bump: minor + - name: substrate-prometheus-endpoint + bump: patch + - name: substrate-frame-rpc-system + bump: patch + - name: minimal-template-node + bump: minor + - name: parachain-template-node + bump: minor + - name: solochain-template-node + bump: minor + - name: polkadot-service + bump: patch + - name: cumulus-client-service + bump: patch + - name: cumulus-test-service + bump: major + - name: polkadot-omni-node-lib + bump: patch diff --git a/prdoc/pr_4826.prdoc b/prdoc/pr_4826.prdoc new file mode 100644 index 000000000000..daa4a77e3e8f --- /dev/null +++ b/prdoc/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/pr_4837.prdoc b/prdoc/pr_4837.prdoc new file mode 100644 index 000000000000..55c12cc92a1c --- /dev/null +++ b/prdoc/pr_4837.prdoc @@ -0,0 +1,26 @@ +# 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 PVF execution priority + +doc: + - audience: Node Dev + description: | + The new logic optimizes the distribution of execution jobs for disputes, approvals, and backings. + The main goal is to create back pressure for backing in the presence of disputes or numerous approval jobs. + +crates: + - name: polkadot-node-core-pvf + bump: major + - name: polkadot-overseer + bump: patch + - name: polkadot-node-subsystem-types + bump: patch + - 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_4982.prdoc b/prdoc/pr_4982.prdoc new file mode 100644 index 000000000000..9e6d103a0ad8 --- /dev/null +++ b/prdoc/pr_4982.prdoc @@ -0,0 +1,13 @@ +title: Add useful error logs in pallet-xcm + +doc: + - audience: Runtime Dev + description: | + This PR adds error logs to assist in debugging pallet-xcm. + Additionally, it replaces the usage of `log` with `tracing`. + +crates: + - name: staging-xcm-executor + bump: patch + - name: pallet-xcm + bump: patch diff --git a/prdoc/pr_5194.prdoc b/prdoc/pr_5194.prdoc new file mode 100644 index 000000000000..afb9d57e79e3 --- /dev/null +++ b/prdoc/pr_5194.prdoc @@ -0,0 +1,11 @@ +title: "FRAME: Support instantiable pallets in tasks." + +doc: + - audience: Runtime Dev + description: | + In FRAME, tasks can now be used in instantiable pallet. Also some fix for expansion with + conditional compilation in construct runtine. + +crates: + - name: frame-support-procedural + bump: patch diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc new file mode 100644 index 000000000000..fb76ce661b4e --- /dev/null +++ b/prdoc/pr_5274.prdoc @@ -0,0 +1,24 @@ +title: Enrich metadata IR with associated types of config traits + +doc: + - audience: Runtime Dev + description: | + This feature is part of the upcoming metadata V16. The associated types of the `Config` trait that require the `TypeInfo` + or `Parameter` bounds are included in the metadata of the pallet. The metadata is not yet exposed to the end-user, however + the metadata intermediate representation (IR) contains these types. + + Developers can opt out of metadata collection of the associated types by specifying `without_metadata` optional attribute + to the `#[pallet::config]`. + + Furthermore, the `without_metadata` argument can be used in combination with the newly added `#[pallet::include_metadata]` + attribute to selectively include only certain associated types in the metadata collection. + +crates: + - name: frame-support + bump: patch + - name: frame-support-procedural + bump: patch + - name: frame-support-procedural-tools + bump: patch + - name: sp-metadata-ir + bump: major diff --git a/prdoc/pr_5311.prdoc b/prdoc/pr_5311.prdoc new file mode 100644 index 000000000000..07affa5cb2ee --- /dev/null +++ b/prdoc/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_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_5390.prdoc b/prdoc/pr_5390.prdoc new file mode 100644 index 000000000000..cfe6894324aa --- /dev/null +++ b/prdoc/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/pr_5420.prdoc b/prdoc/pr_5420.prdoc new file mode 100644 index 000000000000..bf8a34569077 --- /dev/null +++ b/prdoc/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_5435.prdoc b/prdoc/pr_5435.prdoc new file mode 100644 index 000000000000..d3621e385bcd --- /dev/null +++ b/prdoc/pr_5435.prdoc @@ -0,0 +1,16 @@ +title: "Support registering assets on Asset Hubs over bridge" + +doc: + - audience: Runtime User + description: | + Allows one Asset Hub on one side, to register assets on the other Asset Hub over the bridge. + Rococo <> Ethereum test bridge will be dropped in favor of Westend <> Ethereum test bridge. + This PR also changes emulated tests to simulate double bridging from Ethereum<>Westend<>Rococo. + +crates: + - name: assets-common + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch diff --git a/prdoc/pr_5461.prdoc b/prdoc/pr_5461.prdoc new file mode 100644 index 000000000000..bf343216e29b --- /dev/null +++ b/prdoc/pr_5461.prdoc @@ -0,0 +1,20 @@ +title: "runtime: remove ttl" + +doc: + - audience: [Runtime Dev, Node Dev] + description: | + Resolves https://github.com/paritytech/polkadot-sdk/issues/4776. Removes the scheduling ttl used in the relay chain + runtimes, as well as the availability timeout retries. The extrinsics for configuring these two values are also removed. + Deprecates the `ttl` and `max_availability_timeouts` fields of the `HostConfiguration` primitive. + +crates: + - name: polkadot-runtime-parachains + bump: major + - name: polkadot-primitives + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: polkadot + bump: none diff --git a/prdoc/pr_5502.prdoc b/prdoc/pr_5502.prdoc new file mode 100644 index 000000000000..ea9972f01870 --- /dev/null +++ b/prdoc/pr_5502.prdoc @@ -0,0 +1,7 @@ +title: '[pallet-revive] Add pallet to AH westend' +doc: + - audience: Runtime Dev + description: 'Add pallet-revive to Westend runtime, and configure the runtime to accept Ethereum signed transaction' +crates: +- name: asset-hub-westend-runtime + bump: major diff --git a/prdoc/pr_5554.prdoc b/prdoc/pr_5554.prdoc new file mode 100644 index 000000000000..3ebf00b38ed7 --- /dev/null +++ b/prdoc/pr_5554.prdoc @@ -0,0 +1,31 @@ +# 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: Identity Decouple usernames from identities + +doc: + - audience: [Runtime Dev, Runtime User] + description: | + This PR refactors pallet-identity to decouple usernames from identities. Usernames are now + separated from identities in storage, allowing for correct deposit accounting and for + authorities to put up their own deposit to create a username and remove usernames. Various + storage maps had to be refactored and migrated to allow this to happen. The call to remove a + dangling username is now replaced by the permissioned `kill_username` call. + +crates: + - name: pallet-alliance + bump: major + - name: pallet-identity + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: polkadot-runtime-common + bump: major + - name: kitchensink-runtime + bump: major \ No newline at end of file diff --git a/prdoc/pr_5585.prdoc b/prdoc/pr_5585.prdoc new file mode 100644 index 000000000000..d4b115413d4d --- /dev/null +++ b/prdoc/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_5616.prdoc b/prdoc/pr_5616.prdoc new file mode 100644 index 000000000000..16d81c291c30 --- /dev/null +++ b/prdoc/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_5630.prdoc b/prdoc/pr_5630.prdoc new file mode 100644 index 000000000000..bafb9e746d40 --- /dev/null +++ b/prdoc/pr_5630.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: Introduce and Implement the `VestedTransfer` Trait + +doc: + - audience: Runtime Dev + description: | + This PR introduces a new trait `VestedTransfer` which is implemented by `pallet_vesting`. With this, other pallets can easily introduce vested transfers into their logic. + +crates: + - name: frame-support + bump: minor + - name: pallet-vesting + bump: minor 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_5679.prdoc b/prdoc/pr_5679.prdoc new file mode 100644 index 000000000000..59c36ecb933d --- /dev/null +++ b/prdoc/pr_5679.prdoc @@ -0,0 +1,80 @@ +title: Switch to new `CandidateReceipt` primitives +doc: +- audience: + - Node Dev + - Runtime Dev + description: | + This change is just plumbing work and updates all crate interfaces to use the new primitives. + It doesn't alter any functionality and is required before implementing RFC103 on the + node side. +crates: +- name: polkadot-primitives + bump: major +- name: polkadot-runtime-parachains + bump: patch +- name: rococo-runtime + bump: patch +- name: westend-runtime + bump: patch +- name: cumulus-relay-chain-inprocess-interface + bump: major +- name: polkadot-service + bump: patch +- name: polkadot-node-subsystem-types + bump: major +- name: polkadot + bump: patch +- name: cumulus-client-network + bump: major +- name: cumulus-client-pov-recovery + bump: major +- name: cumulus-relay-chain-interface + bump: major +- name: cumulus-relay-chain-minimal-node + bump: major +- name: cumulus-relay-chain-rpc-interface + bump: major +- name: polkadot-node-collation-generation + bump: major +- name: polkadot-node-core-approval-voting + bump: major +- name: polkadot-node-core-av-store + bump: major +- name: polkadot-node-core-backing + bump: major +- name: polkadot-node-core-bitfield-signing + bump: major +- name: polkadot-node-core-candidate-validation + bump: major +- name: polkadot-node-core-dispute-coordinator + bump: major +- name: polkadot-node-core-parachains-inherent + bump: major +- name: polkadot-node-core-prospective-parachains + bump: major +- name: polkadot-node-core-provisioner + bump: major +- name: polkadot-node-core-runtime-api + bump: major +- name: polkadot-availability-distribution + bump: major +- name: polkadot-availability-recovery + bump: major +- name: polkadot-collator-protocol + bump: major +- name: polkadot-dispute-distribution + bump: major +- name: polkadot-node-network-protocol + bump: major +- name: polkadot-statement-distribution + bump: major +- name: polkadot-node-primitives + bump: major +- name: polkadot-node-subsystem-util + bump: major +- name: polkadot-statement-table + bump: major +- name: polkadot-overseer + bump: patch +- name: cumulus-client-consensus-common + bump: major diff --git a/prdoc/pr_5686.prdoc b/prdoc/pr_5686.prdoc new file mode 100644 index 000000000000..3f0da912a34c --- /dev/null +++ b/prdoc/pr_5686.prdoc @@ -0,0 +1,15 @@ +title: "sync: Remove checking of the extrinsics root" + +doc: + - audience: Node Dev + description: | + Remove checking the extrinsics root as part of the sync code. + With the introduction of `system_version` and the possibility to use the `V1` + layout for the trie when calculating the extrinsics root, it would require the + sync code to fetch the runtime version first before knowing which layout to use + when building the extrinsic root. + The extrinsics root is still checked when executing a block on chain. + +crates: + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_5693.prdoc b/prdoc/pr_5693.prdoc new file mode 100644 index 000000000000..d8afae7ba0bc --- /dev/null +++ b/prdoc/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_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_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_5737.prdoc b/prdoc/pr_5737.prdoc new file mode 100644 index 000000000000..a122e4574a9c --- /dev/null +++ b/prdoc/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_5804.prdoc b/prdoc/pr_5804.prdoc new file mode 100644 index 000000000000..beef83860cc5 --- /dev/null +++ b/prdoc/pr_5804.prdoc @@ -0,0 +1,42 @@ +# 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 get_account_id_from_seed / get_from_seed to one common place + +doc: + - audience: Runtime Dev + description: | + `get_account_id_from_seed / get_from_seed` were copied all over the place. This PR removes unnecessary code duplication. + `Keyring::iter()` provides the same functionality and is used instead. + +crates: + - name: polkadot-runtime-common + bump: patch + - name: polkadot-service + bump: major + - name: sp-keyring + bump: major + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: parachains-common + bump: major + - name: emulated-integration-tests-common + bump: major + - name: xcm-emulator + bump: major + - 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: polkadot-parachain-bin + bump: patch + - name: sp-core + bump: patch diff --git a/prdoc/pr_5813.prdoc b/prdoc/pr_5813.prdoc new file mode 100644 index 000000000000..e48f29bbfb63 --- /dev/null +++ b/prdoc/pr_5813.prdoc @@ -0,0 +1,18 @@ +title: "build_struct_json_patch macro added" + +doc: + - audience: Runtime Dev + description: | + This PR adds a macro that allows to construct a RuntimeGenesisConfig preset + containing only provided fields, while performing the validation of the + entire struct. + + Related issue: https://github.com/paritytech/polkadot-sdk/issues/5700 + +crates: + - name: frame-support + bump: minor + - name: asset-hub-rococo-runtime + bump: patch + - name: westend-runtime + bump: patch 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_5847.prdoc b/prdoc/pr_5847.prdoc new file mode 100644 index 000000000000..fdbf6423da60 --- /dev/null +++ b/prdoc/pr_5847.prdoc @@ -0,0 +1,19 @@ +title: '`candidate-validation`: RFC103 implementation' +doc: +- audience: Node Dev + description: | + Introduces support for new v2 descriptor `core_index` and `session_index` fields. + The subsystem will check the values of the new fields only during backing validations. +crates: +- name: polkadot-node-primitives + bump: major +- name: polkadot-primitives + bump: major +- name: cumulus-relay-chain-inprocess-interface + bump: minor +- name: cumulus-relay-chain-interface + bump: minor +- name: cumulus-client-consensus-aura + bump: minor +- name: polkadot-node-core-candidate-validation + bump: major diff --git a/prdoc/pr_5856.prdoc b/prdoc/pr_5856.prdoc new file mode 100644 index 000000000000..383e95e3da88 --- /dev/null +++ b/prdoc/pr_5856.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: Extend state tracking of chainHead to capture notification gaps + +doc: + - audience: Node Dev + description: | + This PR extends the state tracking of the RPC-v2 chainHead methods. + ChainHead tracks the reported blocks to detect notification gaps. + This state tracking ensures we can detect `NewBlock` events for + which we did not report previously the parent hash. + +crates: + - name: sc-rpc-spec-v2 + bump: minor + diff --git a/prdoc/pr_5866.prdoc b/prdoc/pr_5866.prdoc new file mode 100644 index 000000000000..44fffe1d2129 --- /dev/null +++ b/prdoc/pr_5866.prdoc @@ -0,0 +1,23 @@ +title: "[pallet-revive] Ethereum JSON-RPC integration" + +doc: + - audience: Runtime Dev + description: | + Related PR: https://github.com/paritytech/revive-ethereum-rpc/pull/5 + + Changes Included: + - A new pallet::call eth_transact. + - A custom UncheckedExtrinsic struct to dispatch unsigned eth_transact calls from an Ethereum JSON-RPC proxy. + - Generated types and traits to support implementing a JSON-RPC Ethereum proxy. +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-mock-network + bump: patch + - name: pallet-revive-uapi + bump: patch + - name: polkadot-sdk + bump: patch + diff --git a/prdoc/pr_5872.prdoc b/prdoc/pr_5872.prdoc new file mode 100644 index 000000000000..cf4f0b24f8db --- /dev/null +++ b/prdoc/pr_5872.prdoc @@ -0,0 +1,13 @@ +title: '[omni-bencher] Make all runtimes work' +doc: +- audience: Runtime Dev + description: |- + Changes: + - Add `--exclude-pallets` to exclude some pallets from runtimes where we dont have genesis presets yet + - Make `--genesis-builder-policy=none` work with `--runtime` + - CI: Run the frame-omni-bencher for all runtimes +crates: +- name: frame-benchmarking-cli + bump: major +- name: contracts-rococo-runtime + bump: patch diff --git a/prdoc/pr_5876.prdoc b/prdoc/pr_5876.prdoc new file mode 100644 index 000000000000..4e2b8a5c8aad --- /dev/null +++ b/prdoc/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_5883.prdoc b/prdoc/pr_5883.prdoc new file mode 100644 index 000000000000..96225a89bc99 --- /dev/null +++ b/prdoc/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/pr_5886.prdoc new file mode 100644 index 000000000000..f5e597281197 --- /dev/null +++ b/prdoc/pr_5886.prdoc @@ -0,0 +1,18 @@ +title: Bump some dependencies +doc: +- audience: Runtime Dev + description: |- + This bumps `ethbloom`, `ethereum-types`, `primitive-types` and `rlp` to their latest version. + + Fixes: https://github.com/paritytech/polkadot-sdk/issues/5870 +crates: +- name: sc-consensus-babe + bump: patch +- name: pallet-babe + bump: patch +- name: pallet-revive + bump: patch +- name: sp-runtime + bump: patch +- name: bp-polkadot-core + bump: major diff --git a/prdoc/pr_5888.prdoc b/prdoc/pr_5888.prdoc new file mode 100644 index 000000000000..9552eada6915 --- /dev/null +++ b/prdoc/pr_5888.prdoc @@ -0,0 +1,16 @@ +title: 'parachain-system: send core selector ump signal' + +doc: + - audience: Runtime Dev + description: | + Send the core selector ump signal in cumulus. Guarded by a compile time feature called `experimental-ump-signals` + until nodes are upgraded to a version that includes https://github.com/paritytech/polkadot-sdk/pull/5423 for + gracefully handling ump signals. + +crates: + - name: cumulus-client-consensus-aura + bump: minor + - name: cumulus-pallet-parachain-system + bump: major + - name: cumulus-primitives-core + bump: minor diff --git a/prdoc/pr_5891.prdoc b/prdoc/pr_5891.prdoc new file mode 100644 index 000000000000..4f8252628eb4 --- /dev/null +++ b/prdoc/pr_5891.prdoc @@ -0,0 +1,33 @@ +# 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 benchmark overhead command to frame-omni-bencher + +doc: + - audience: Runtime Dev + description: | + This adds the benchmark overhead command to the `frame-omni-bencher` library. This allows + para- and relay chain teams to generate extrinsic and block base weights. + +crates: + - name: sc-chain-spec + bump: minor + - name: polkadot-service + bump: major + - name: frame-benchmarking-cli + bump: major + - name: cumulus-client-parachain-inherent + bump: patch + - name: polkadot-cli + bump: patch + - name: polkadot-omni-node-lib + bump: patch + - name: polkadot-omni-node + bump: patch + - name: polkadot-parachain-bin + bump: patch + - name: polkadot + bump: patch + - name: frame-omni-bencher + bump: minor + diff --git a/prdoc/pr_5892.prdoc b/prdoc/pr_5892.prdoc new file mode 100644 index 000000000000..b909e443328b --- /dev/null +++ b/prdoc/pr_5892.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: "Treasury: add migration to clean up unapproved deprecated proposals" + +doc: + - audience: Runtime Dev + description: | + It is no longer possible to create `Proposals` storage item in `pallet-treasury` due to migration from + governance v1 model but there are some `Proposals` whose bonds are still on hold with no way to release them. + The purpose of this migration is to clear `Proposals` which are stuck and return bonds to the proposers. + +crates: + - name: pallet-treasury + bump: patch + - name: rococo-runtime + bump: patch diff --git a/prdoc/pr_5908.prdoc b/prdoc/pr_5908.prdoc new file mode 100644 index 000000000000..8f05819451a0 --- /dev/null +++ b/prdoc/pr_5908.prdoc @@ -0,0 +1,14 @@ +title: "collation-generation: use v2 receipts" + +doc: + - audience: Node Dev + description: | + Implementation of [RFC 103](https://github.com/polkadot-fellows/RFCs/pull/103) for the collation-generation subsystem. + Also removes the usage of AsyncBackingParams. + +crates: + - name: polkadot-node-collation-generation + bump: major + validate: false + - name: polkadot-primitives + bump: minor diff --git a/prdoc/pr_5915.prdoc b/prdoc/pr_5915.prdoc new file mode 100644 index 000000000000..a9303e2563d1 --- /dev/null +++ b/prdoc/pr_5915.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: Omni-Node renamings + +doc: + - audience: Node Dev + description: | + This PR renames the `polkadot-parachain-lib` crate to `polkadot-omni-node-lib` and introduces a new + `polkadot-omni-node` binary. + +crates: + - name: polkadot-omni-node-lib + bump: patch + - name: polkadot-parachain-bin + bump: patch + - name: polkadot-sdk + bump: patch diff --git a/prdoc/pr_5919.prdoc b/prdoc/pr_5919.prdoc new file mode 100644 index 000000000000..1b48a24a9e28 --- /dev/null +++ b/prdoc/pr_5919.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: "substrate-offchain: upgrade hyper to v1" + +doc: + - audience: Node Dev + description: | + Bump depencency `hyper` of `substrait-offchain` for http from `0.14` to `1`. + This changed APIs a bit; + - `sc_offchain::Offchainworker::new()` now returns `std::io::Result` (Previously was `Self`) + +crates: + - name: sc-offchain + bump: major + - name: polkadot-service + bump: patch + - name: staging-node-cli + bump: patch diff --git a/prdoc/pr_5924.prdoc b/prdoc/pr_5924.prdoc new file mode 100644 index 000000000000..26bde8eec0de --- /dev/null +++ b/prdoc/pr_5924.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: Bump PoV request timeout + +doc: + - audience: Node Dev + description: | + With asynchronous backing and PoV size 10MB, we can increase the PoV request timeout from 1.2s to 2s. + +crates: + - name: polkadot-node-network-protocol + bump: patch diff --git a/prdoc/pr_5939.prdoc b/prdoc/pr_5939.prdoc new file mode 100644 index 000000000000..babb26281ecd --- /dev/null +++ b/prdoc/pr_5939.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] Bump PolkaVM and add static code validation" + +doc: + - audience: Runtime Dev + description: | + Statically validate basic block sizes and instructions. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: minor + - name: pallet-revive-uapi + bump: patch diff --git a/prdoc/pr_5941.prdoc b/prdoc/pr_5941.prdoc new file mode 100644 index 000000000000..4e88400f4ef0 --- /dev/null +++ b/prdoc/pr_5941.prdoc @@ -0,0 +1,16 @@ +title: "`SolochainDefaultConfig`: Use correct `AccountData`" + +doc: + - audience: Runtime Dev + description: | + `SolochainDefaultConfig` by default was setting `AccountData` to `AccountInfo`. + Thus, the actual account data was recursively nested the same type. By default + it should be set `()`, because this is the only reasonable `AccountData`. + + If you have used `SolochainDefaultConfig` before and did not overwrite, `AccountData` + you should now overwrite it to `AccountInfo` or you will need to write a migration to + change the data. + +crates: + - name: frame-system + bump: patch diff --git a/prdoc/pr_5946.prdoc b/prdoc/pr_5946.prdoc new file mode 100644 index 000000000000..9a858c980a19 --- /dev/null +++ b/prdoc/pr_5946.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: "[FRAME] fix: Do not emit `Issued { amount: 0 }` event" + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + Filter out `Issued` events in `pallet-balances` module when its balance amount is zero. + +crates: + - name: pallet-balances + bump: patch diff --git a/prdoc/pr_5954.prdoc b/prdoc/pr_5954.prdoc new file mode 100644 index 000000000000..2c9efcce7a6a --- /dev/null +++ b/prdoc/pr_5954.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: "templates: make node compilation optional" + +doc: + - audience: [Node Dev, Runtime Dev] + description: | + Node compilation for minimal and parachain templates is made optional, not part of the + templates `default-members` list. At the same time, we introduce OmniNode as alternative + to run the templates. + +crates: + - name: polkadot-omni-node + bump: patch + - name: polkadot-omni-node-lib + bump: patch + - name: staging-chain-spec-builder + bump: patch diff --git a/prdoc/pr_5961.prdoc b/prdoc/pr_5961.prdoc new file mode 100644 index 000000000000..46a5be8e49d5 --- /dev/null +++ b/prdoc/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/pr_5971.prdoc b/prdoc/pr_5971.prdoc new file mode 100644 index 000000000000..4b1afc4c268a --- /dev/null +++ b/prdoc/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/pr_5984.prdoc b/prdoc/pr_5984.prdoc new file mode 100644 index 000000000000..3b6651bac6b9 --- /dev/null +++ b/prdoc/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/pr_5994.prdoc new file mode 100644 index 000000000000..425653e52646 --- /dev/null +++ b/prdoc/pr_5994.prdoc @@ -0,0 +1,3 @@ +crates: + - name: sc-consensus-babe + bump: none diff --git a/prdoc/pr_5995.prdoc b/prdoc/pr_5995.prdoc new file mode 100644 index 000000000000..fdd754057bd1 --- /dev/null +++ b/prdoc/pr_5995.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: Use frame umbrella crate in pallet-proxy and pallet-multisig + +doc: + - audience: Runtime Dev + description: | + Extends the FRAME umbrella crate and uses it in pallet-proxy and pallet-multisig. + Migrates benchmarking from v1 to v2 for pallet-proxy and pallet-multisig. + Allows CI to pick the umbrella crate weights template to run benchmarks. + +crates: + - name: pallet-multisig + bump: minor + - name: pallet-proxy + bump: minor + - name: polkadot-sdk-frame + bump: major + - name: pallet-migrations + bump: patch diff --git a/prdoc/pr_5998.prdoc b/prdoc/pr_5998.prdoc new file mode 100644 index 000000000000..e3279051ca6a --- /dev/null +++ b/prdoc/pr_5998.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 memory leak in litep2p public addresses + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + This PR bounds the number of public addresses of litep2p to 32 entries. + This ensures we do not increase the number of addresses over time, and that the DHT + authority records will not exceed the upper size limit. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/pr_5999.prdoc b/prdoc/pr_5999.prdoc new file mode 100644 index 000000000000..5252de6289d1 --- /dev/null +++ b/prdoc/pr_5999.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: "Westend: Constant yearly emission" + +doc: + - audience: Runtime User + description: | + Integrating the new inflation approach from https://github.com/polkadot-fellows/runtimes/pull/471 + into Westend first to check that it is working. + + +crates: + - name: westend-runtime + bump: patch diff --git a/prdoc/pr_6011.prdoc b/prdoc/pr_6011.prdoc new file mode 100644 index 000000000000..e053b607085f --- /dev/null +++ b/prdoc/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/pr_6015.prdoc new file mode 100644 index 000000000000..d5a7d1e18d5d --- /dev/null +++ b/prdoc/pr_6015.prdoc @@ -0,0 +1,9 @@ +title: Rename QueueEvent::StartWork +doc: +- audience: Node Dev + description: |- + When we send `QueueEvent::StartWork`, we have already completed the execution. Therefore, `QueueEvent::FinishWork` is a better match. + +crates: +- name: polkadot-node-core-pvf + bump: patch diff --git a/prdoc/pr_6016.prdoc b/prdoc/pr_6016.prdoc new file mode 100644 index 000000000000..967c3a766068 --- /dev/null +++ b/prdoc/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/pr_6022.prdoc new file mode 100644 index 000000000000..804d46af6613 --- /dev/null +++ b/prdoc/pr_6022.prdoc @@ -0,0 +1,14 @@ +title: '[Coretime chain] Add high assignment count mitigation to testnets' +doc: +- audience: Runtime User + description: | + We can handle a maximum of 28 assignments inside one XCM, while it's possible to have 80 (if a + region is interlaced 79 times). This can be chunked on the coretime chain side but currently the + relay does not support this. This PR truncates the additional assignments on Rococo and Westend + to mitigate this until the relay is fixed. The first 27 assignments are taken, the final 28th is + used to pad with idle to complete the mask. Any other assignments are dropped. +crates: +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch diff --git a/prdoc/pr_6023.prdoc b/prdoc/pr_6023.prdoc new file mode 100644 index 000000000000..3b3b5a4cb5fd --- /dev/null +++ b/prdoc/pr_6023.prdoc @@ -0,0 +1,11 @@ +title: Fix storage in pallet section + +doc: + - audience: Runtime Dev + description: | + Fix compilation of `pallet::storage` in a pallet section: a local binding definition was not + correctly referenced due to macro hygiene. + +crates: + - name: frame-support-procedural + bump: patch diff --git a/prdoc/pr_6025.prdoc b/prdoc/pr_6025.prdoc new file mode 100644 index 000000000000..64072c0ae632 --- /dev/null +++ b/prdoc/pr_6025.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: Refactor staking pallet benchmarks to `v2` + +doc: + - audience: Runtime Dev + description: | + Update benchmarks in staking pallet to the second version of the `frame_benchmarking` runtime benchmarking framework. + +crates: + - name: pallet-staking + bump: patch \ No newline at end of file diff --git a/prdoc/pr_6027.prdoc b/prdoc/pr_6027.prdoc new file mode 100644 index 000000000000..36bdb57b25f5 --- /dev/null +++ b/prdoc/pr_6027.prdoc @@ -0,0 +1,9 @@ +title: Remove pallet::getter from pallet-offences +doc: + - audience: Runtime Dev + description: | + This PR removes pallet::getter from pallet-offences from type Reports. It also adds a test to verify that retrieval of Reports still works with storage::getter. + +crates: + - name: pallet-offences + bump: patch diff --git a/prdoc/pr_6032.prdoc b/prdoc/pr_6032.prdoc new file mode 100644 index 000000000000..ed47750f8fd7 --- /dev/null +++ b/prdoc/pr_6032.prdoc @@ -0,0 +1,11 @@ +title: Fix `feeless_if` in pallet section + +doc: + - audience: Runtime Dev + description: | + Fix compilation with `pallet::feeless_if` in a pallet section: a local binding unexpectely + resolved to a macro definition. + +crates: + - name: frame-support-procedural + bump: patch diff --git a/prdoc/pr_6039.prdoc b/prdoc/pr_6039.prdoc new file mode 100644 index 000000000000..e14ea8f3e17b --- /dev/null +++ b/prdoc/pr_6039.prdoc @@ -0,0 +1,54 @@ +# 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 Trusted Query API calls." + +doc: + - audience: Runtime Dev + description: | + Added is_trusted_reserve and is_trusted_teleporter API calls to all the runtimes. + Given an asset and a location, they return if the chain trusts that location as a reserve or teleporter for that asset respectively. + You can implement them on your runtime by simply calling a helper function on `pallet-xcm`. + ```rust + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + ``` + + - audience: Runtime User + description: | + There's a new runtime API to check if a chain trust a Location as a reserve or teleporter for a given Asset. + It's implemented in all the relays and system parachains in Westend and Rococo. + +crates: + - name: asset-hub-westend-runtime + bump: minor + - name: bridge-hub-rococo-runtime + bump: minor + - name: bridge-hub-westend-runtime + bump: minor + - name: collectives-westend-runtime + bump: minor + - name: contracts-rococo-runtime + bump: minor + - name: coretime-rococo-runtime + bump: minor + - name: coretime-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: minor + - name: people-westend-runtime + bump: minor + - name: penpal-runtime + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: pallet-xcm + bump: minor + - name: xcm-runtime-apis + bump: minor diff --git a/prdoc/pr_6045.prdoc b/prdoc/pr_6045.prdoc new file mode 100644 index 000000000000..d1b3fb4e77f2 --- /dev/null +++ b/prdoc/pr_6045.prdoc @@ -0,0 +1,10 @@ +title: '[pallet-revive] ensure the return data is reset if no frame was instantiated' + +doc: +- audience: + - Runtime Dev + description: Failed call frames do not produce new return data but still reset it. + +crates: +- name: pallet-revive + bump: patch diff --git a/prdoc/pr_6058.prdoc b/prdoc/pr_6058.prdoc new file mode 100644 index 000000000000..5b99467b413f --- /dev/null +++ b/prdoc/pr_6058.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: backpressure `chainhead_v1_follow` + +doc: + - audience: Node Operator + description: | + The RPC endpoint `chainHead_v1_follow` now relies on backpressure + to determine whether or not the subscription should be closed instead of continuing to send more events + to a consumer which can't keep up. + This should significantly improve memory consumption as substrate will be keeping less messages in memory. + +crates: + - name: sc-rpc-spec-v2 + bump: major + - name: sc-rpc + bump: major diff --git a/prdoc/pr_6061.prdoc b/prdoc/pr_6061.prdoc new file mode 100644 index 000000000000..742e69ea9eca --- /dev/null +++ b/prdoc/pr_6061.prdoc @@ -0,0 +1,10 @@ +title: Remove check-migrations for rococo chain + +doc: + - audience: [Runtime User] + description: | + This PR adds the missing `cumulus_pallet_xcmp_queue` v5 migration to the coretime-westend runtime. + +crates: +- name: coretime-westend-runtime + bump: none diff --git a/prdoc/pr_6073.prdoc b/prdoc/pr_6073.prdoc new file mode 100644 index 000000000000..d83967f9b975 --- /dev/null +++ b/prdoc/pr_6073.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: Refactor `pallet-grandpa` benchmarks to `v2` + +doc: + - audience: Runtime Dev + description: | + Update benchmarks in GRANDPA pallet to use the second version of the `frame_benchmarking` runtime benchmarking framework. + +crates: + - name: pallet-grandpa + bump: patch \ No newline at end of file diff --git a/prdoc/pr_6077.prdoc b/prdoc/pr_6077.prdoc new file mode 100644 index 000000000000..f222fb27ce07 --- /dev/null +++ b/prdoc/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/pr_6080.prdoc new file mode 100644 index 000000000000..52ecd58dddde --- /dev/null +++ b/prdoc/pr_6080.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: Assets in pool with native can be used in query_weight_to_asset_fee in Asset Hubs + +doc: + - audience: Runtime User + description: | + `query_weight_to_asset_fee` now works with assets in a pool with the native asset in both + Westend and Rococo asset hubs. + This means all the information you get from `query_acceptable_payment_assets` can be used + directly in `query_weight_to_asset_fee` to get the correct fees that need to be paid. + +crates: + - name: assets-common + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: emulated-integration-tests-common + bump: minor diff --git a/prdoc/pr_6087.prdoc b/prdoc/pr_6087.prdoc new file mode 100644 index 000000000000..db083ba645b9 --- /dev/null +++ b/prdoc/pr_6087.prdoc @@ -0,0 +1,12 @@ +title: Expose private structs in pallet_nfts and pallet_uniques. + +doc: + - audience: Runtime Dev + description: | + PR changes certain structs in pallet_nfts and pallet_uniques into public. It also changes 2 storages (collection & asset metadata) into public in pallet_uniques. + +crates: + - name: pallet-nfts + bump: patch + - name: pallet-uniques + bump: patch diff --git a/prdoc/pr_6088.prdoc b/prdoc/pr_6088.prdoc new file mode 100644 index 000000000000..93e435bbd458 --- /dev/null +++ b/prdoc/pr_6088.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] EXTCODEHASH to match EIP-1052" + +doc: + - audience: Runtime Dev + description: | + Update `ext_code_hash` to match [EIP-1052](https://eips.ethereum.org/EIPS/eip-1052) specs. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6094.prdoc b/prdoc/pr_6094.prdoc new file mode 100644 index 000000000000..23391c889155 --- /dev/null +++ b/prdoc/pr_6094.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: Polkadot OmniNode Docs + +doc: + - audience: ... + description: | + Adds documentation in https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html and rust-docs for polkadot-omni-node project. + +crates: + - name: sp-genesis-builder + bump: patch + - name: pallet-aura + bump: patch + - name: polkadot-omni-node-lib + bump: patch + - name: polkadot-sdk-frame # since the crate is "experimental, we don't need to bump yet." + bump: major + - name: polkadot-omni-node + bump: patch diff --git a/prdoc/pr_6096.prdoc b/prdoc/pr_6096.prdoc new file mode 100644 index 000000000000..c77c323a2e08 --- /dev/null +++ b/prdoc/pr_6096.prdoc @@ -0,0 +1,15 @@ +title: 'pallet-revive: Add stateful address mapping' +doc: +- audience: + - Runtime Dev + description: |- + Fixes #5576 + + This allows contracts to be used with an AccountId32 through normal extrinsics and not only through the eth compat layer. It works by adding a new extrinsic `map_account` that lets people register their AccountId32. +crates: +- name: pallet-revive-fixtures + bump: minor +- name: pallet-revive-mock-network + bump: patch +- name: pallet-revive + bump: major diff --git a/prdoc/pr_6104.prdoc b/prdoc/pr_6104.prdoc new file mode 100644 index 000000000000..2b62a68c9f0e --- /dev/null +++ b/prdoc/pr_6104.prdoc @@ -0,0 +1,10 @@ +title: "LocalTransactionPool implemented for fork aware transaction pool" + +doc: + - audience: Node Dev + description: | + LocalTransactionPool trait is implemented for fork aware transaction pool. + +crates: + - name: sc-transaction-pool + bump: minor diff --git a/prdoc/pr_6105.prdoc b/prdoc/pr_6105.prdoc new file mode 100644 index 000000000000..f8339c6ce535 --- /dev/null +++ b/prdoc/pr_6105.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] implement tx origin API' + +doc: +- audience: + - Runtime Dev + description: Implement a syscall to retreive the transaction origin. + +crates: +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor +- name: pallet-revive-fixtures + 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_6129.prdoc b/prdoc/pr_6129.prdoc new file mode 100644 index 000000000000..61719c213e8d --- /dev/null +++ b/prdoc/pr_6129.prdoc @@ -0,0 +1,32 @@ +# 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: "Improved TrustedQueryAPI signatures." + +doc: + - audience: Runtime Dev + description: | + Changed returned type of API methods from `Result` to a typed one: + `type XcmTrustedQueryResult = Result` + +crates: + - 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: people-rococo-runtime + bump: patch + - name: people-westend-runtime + bump: patch + - name: penpal-runtime + bump: patch diff --git a/prdoc/pr_6141.prdoc b/prdoc/pr_6141.prdoc new file mode 100644 index 000000000000..d9994ac4f842 --- /dev/null +++ b/prdoc/pr_6141.prdoc @@ -0,0 +1,11 @@ +title: Improve `CheckMetadataHash` transaction extension weight and logic + +doc: + - audience: Runtime Dev + description: | + The compilation now panics if the optional compile-time environment variable `RUNTIME_METADATA_HASH` contains an invalid value. + The weight for the `CheckMetadataHash` transaction extension is more accurate as it is almost compile-time. + +crates: +- name: frame-metadata-hash-extension + bump: minor diff --git a/prdoc/pr_6147.prdoc b/prdoc/pr_6147.prdoc new file mode 100644 index 000000000000..eef0d0936675 --- /dev/null +++ b/prdoc/pr_6147.prdoc @@ -0,0 +1,17 @@ +title: "[pallet-revive] Ethereum JSON-RPC" + +doc: + - audience: Runtime Dev + description: | + Add a new Ethereum JSON-RPC server that can be used a substrate chain configured with pallet-revive +crates: + - name: pallet-revive + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: pallet-revive-eth-rpc + bump: patch + - name: pallet-revive-fixtures + bump: patch + - name: polkadot-sdk + bump: patch diff --git a/prdoc/pr_6148.prdoc b/prdoc/pr_6148.prdoc new file mode 100644 index 000000000000..430a58dfefbb --- /dev/null +++ b/prdoc/pr_6148.prdoc @@ -0,0 +1,17 @@ +title: Fix migrations for pallet-xcm +doc: +- audience: Runtime Dev + description: |- + `pallet-xcm` stores some operational data that uses `Versioned*` XCM types. When we add a new XCM version (XV), we deprecate XV-2 and remove XV-3. + This PR extends the existing `MigrateToLatestXcmVersion` to include migration for the `Queries`, `LockedFungibles`, and `RemoteLockedFungibles` storage types. + Additionally, more checks were added to `try_state` for these types. + +crates: +- name: westend-runtime + bump: patch +- name: staging-xcm-builder + bump: none +- name: xcm-runtime-apis + bump: none +- name: pallet-xcm + bump: patch diff --git a/prdoc/pr_6156.prdoc b/prdoc/pr_6156.prdoc new file mode 100644 index 000000000000..d20324a83a2f --- /dev/null +++ b/prdoc/pr_6156.prdoc @@ -0,0 +1,23 @@ +title: "Use bool::then instead of then_some with function calls" +doc: +- audience: Node Dev + description: |- + Fix misusage of `bool::then_some`. + +crates: +- name: polkadot-omni-node-lib + bump: patch +- name: polkadot-cli + bump: patch +- name: polkadot-collator-protocol + bump: patch +- name: sc-network + bump: patch +- name: sc-network-sync + bump: patch +- name: pallet-contracts-proc-macro + bump: patch +- name: frame-support-procedural + bump: patch +- name: frame-support + bump: patch 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_6169.prdoc b/prdoc/pr_6169.prdoc new file mode 100644 index 000000000000..0416fe008051 --- /dev/null +++ b/prdoc/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/pr_6171.prdoc new file mode 100644 index 000000000000..36246350cf8a --- /dev/null +++ b/prdoc/pr_6171.prdoc @@ -0,0 +1,7 @@ +title: 'remove parachains_assigner' +doc: + - audience: Runtime Dev + description: "Remove the code of the parachains_assigner pallet, since coretime was released on all production networks." +crates: +- name: polkadot-runtime-parachains + bump: major diff --git a/prdoc/pr_6174.prdoc b/prdoc/pr_6174.prdoc new file mode 100644 index 000000000000..8aa1c25012b1 --- /dev/null +++ b/prdoc/pr_6174.prdoc @@ -0,0 +1,9 @@ +title: '[pallet-revive] fix fixture build path' +doc: +- audience: Runtime Dev + description: "Fix fixture build path" +crates: +- name: pallet-revive-fixtures + bump: patch +- name: pallet-revive + 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_6187.prdoc b/prdoc/pr_6187.prdoc new file mode 100644 index 000000000000..92d801987969 --- /dev/null +++ b/prdoc/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/pr_6192.prdoc new file mode 100644 index 000000000000..cd9255486706 --- /dev/null +++ b/prdoc/pr_6192.prdoc @@ -0,0 +1,7 @@ +title: '[pallet-revive] fix hardcoded gas in tests' +doc: +- audience: Runtime Dev + description: Fix hardcoded gas limits in tests +crates: +- name: pallet-revive + bump: patch diff --git a/prdoc/pr_6205.prdoc b/prdoc/pr_6205.prdoc new file mode 100644 index 000000000000..0874eb468db4 --- /dev/null +++ b/prdoc/pr_6205.prdoc @@ -0,0 +1,8 @@ +title: 'pallet-message-queue: Fix max message size calculation' +doc: +- audience: Runtime Dev + description: |- + The max size of a message should not depend on the weight left in a given execution context. Instead the max message size depends on the service weights configured for the pallet. A message that may does not fit into `on_idle` is not automatically overweight, because it may can be executed successfully in `on_initialize` or in another block in `on_idle` when there is more weight left. +crates: +- name: pallet-message-queue + bump: patch diff --git a/prdoc/pr_6212.prdoc b/prdoc/pr_6212.prdoc new file mode 100644 index 000000000000..97f522025d1e --- /dev/null +++ b/prdoc/pr_6212.prdoc @@ -0,0 +1,32 @@ +# 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 Trusted Query API calls for Westend and Rococo chains" + +doc: + - audience: Runtime Dev + description: | + Added is_trusted_reserve and is_trusted_teleporter API calls to relay chains. + Given an asset and a location, they return if the chain trusts that location as a reserve or teleporter for that asset respectively. + You can implement them on your runtime by simply calling a helper function on `pallet-xcm`. + ```rust + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + ``` + + - audience: Runtime User + description: | + There's a new runtime API to check if a chain trust a Location as a reserve or teleporter for a given Asset. + It's implemented in all the relays and system parachains in Westend and Rococo. + +crates: + - name: westend-runtime + bump: minor + - name: rococo-runtime + bump: minor diff --git a/prdoc/pr_6214.prdoc b/prdoc/pr_6214.prdoc new file mode 100644 index 000000000000..c991df986307 --- /dev/null +++ b/prdoc/pr_6214.prdoc @@ -0,0 +1,5 @@ +crates: + - name: cumulus-pallet-parachain-system + bump: none + - name: rococo-parachain-runtime + bump: none 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_6217.prdoc b/prdoc/pr_6217.prdoc new file mode 100644 index 000000000000..2fa800b58d2c --- /dev/null +++ b/prdoc/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/pr_6218.prdoc new file mode 100644 index 000000000000..5c97c926f238 --- /dev/null +++ b/prdoc/pr_6218.prdoc @@ -0,0 +1,9 @@ +title: Enable approval-voting-parallel by default on kusama + +doc: + - audience: Node Dev + description: | + Enable approval-voting-parallel by default on kusama +crates: + - name: polkadot-service + bump: patch 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_6221.prdoc b/prdoc/pr_6221.prdoc new file mode 100644 index 000000000000..57c81b322f92 --- /dev/null +++ b/prdoc/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/pr_6228.prdoc b/prdoc/pr_6228.prdoc new file mode 100644 index 000000000000..4512adf01bbb --- /dev/null +++ b/prdoc/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/pr_6246.prdoc new file mode 100644 index 000000000000..3fc268749f37 --- /dev/null +++ b/prdoc/pr_6246.prdoc @@ -0,0 +1,13 @@ +title: '[pallet-revive] implement the block hash API' +doc: +- audience: Runtime Dev + description: |- + - Bound T::Hash to H256 + - Implement the block hash API +crates: +- name: pallet-revive + bump: major +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive-uapi + bump: major 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_6255.prdoc b/prdoc/pr_6255.prdoc new file mode 100644 index 000000000000..7b69717b5c2d --- /dev/null +++ b/prdoc/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/pr_6257.prdoc b/prdoc/pr_6257.prdoc new file mode 100644 index 000000000000..45f9810108ef --- /dev/null +++ b/prdoc/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/pr_6260.prdoc new file mode 100644 index 000000000000..d49b3706873b --- /dev/null +++ b/prdoc/pr_6260.prdoc @@ -0,0 +1,12 @@ +title: '[pallet-revive] code size API' +doc: +- audience: Runtime Dev + description: This PR implements the contract API to query the code size of a given + address. +crates: +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor +- name: pallet-revive-fixtures + bump: minor diff --git a/prdoc/pr_6261.prdoc b/prdoc/pr_6261.prdoc new file mode 100644 index 000000000000..20ee5563bcfd --- /dev/null +++ b/prdoc/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_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_6263.prdoc b/prdoc/pr_6263.prdoc new file mode 100644 index 000000000000..1b1da78c85a2 --- /dev/null +++ b/prdoc/pr_6263.prdoc @@ -0,0 +1,10 @@ +title: '[pallet-revive] Update typeInfo' +doc: +- audience: Runtime Dev + description: |- + Update typeinfo impl to make it transparent for subxt + + see https://github.com/paritytech/subxt/pull/1845 +crates: +- name: pallet-revive + bump: minor diff --git a/prdoc/pr_6264.prdoc b/prdoc/pr_6264.prdoc new file mode 100644 index 000000000000..59bdd9da7fac --- /dev/null +++ b/prdoc/pr_6264.prdoc @@ -0,0 +1,12 @@ +title: 'pallet-revive: Trade code size for call stack depth' +doc: +- audience: Runtime Dev + description: This will reduce the call stack depth in order to raise the allowed + code size. Should allow around 100KB of instructions. This is necessary to stay + within the memory envelope. More code size is more appropriate for testing right + now. We will re-evaluate parameters once we have 64bit support. +crates: +- name: pallet-revive-fixtures + bump: major +- name: pallet-revive + bump: major diff --git a/prdoc/pr_6268.prdoc b/prdoc/pr_6268.prdoc new file mode 100644 index 000000000000..cfa44c24533c --- /dev/null +++ b/prdoc/pr_6268.prdoc @@ -0,0 +1,10 @@ +title: Bump a timeout in zombienet coretime smoke test +doc: +- audience: Node Dev + description: |- + polkadot/zombienet_tests/smoke/0004-coretime-smoke-test.zndsl still timeouts on CI from time to time. Bumping the timeout a bit more. + + Related to https://github.com/paritytech/polkadot-sdk/issues/6226 +crates: +- name: polkadot + bump: none diff --git a/prdoc/pr_6278.prdoc b/prdoc/pr_6278.prdoc new file mode 100644 index 000000000000..d841129aa063 --- /dev/null +++ b/prdoc/pr_6278.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] rpc server add docker file' +doc: +- audience: Runtime Dev + description: |- + Add a docker for pallet-revive eth-rpc + + Tested with + ``` + sudo docker build . -t eth-rpc -f substrate/frame/revive/rpc/Dockerfile + sudo docker run --network="host" -e RUST_LOG="info,eth-rpc=debug" eth-rpc + ``` +crates: +- name: pallet-revive-eth-rpc + 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_6288.prdoc b/prdoc/pr_6288.prdoc new file mode 100644 index 000000000000..8c1ed920efc3 --- /dev/null +++ b/prdoc/pr_6288.prdoc @@ -0,0 +1,7 @@ +title: '[pallet-revive] Add metrics to eth-rpc' +doc: +- audience: Runtime Dev + description: Add metrics for eth-rpc +crates: +- name: pallet-revive-eth-rpc + bump: minor 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_6291.prdoc b/prdoc/pr_6291.prdoc new file mode 100644 index 000000000000..73053c9d47bd --- /dev/null +++ b/prdoc/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/pr_6295.prdoc b/prdoc/pr_6295.prdoc new file mode 100644 index 000000000000..c7e4282208ee --- /dev/null +++ b/prdoc/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/pr_6296.prdoc new file mode 100644 index 000000000000..dcc4ad9095f6 --- /dev/null +++ b/prdoc/pr_6296.prdoc @@ -0,0 +1,8 @@ +title: Migrate pallet-glutton benchmark to v2 +doc: +- audience: Runtime Dev + description: |- + Update `pallet-glutton` to benchmarks v2. +crates: +- name: pallet-glutton + bump: patch diff --git a/prdoc/pr_6298.prdoc b/prdoc/pr_6298.prdoc new file mode 100644 index 000000000000..fa8d73b11943 --- /dev/null +++ b/prdoc/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/pr_6299.prdoc b/prdoc/pr_6299.prdoc new file mode 100644 index 000000000000..fe8906f6e153 --- /dev/null +++ b/prdoc/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/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_6304.prdoc b/prdoc/pr_6304.prdoc new file mode 100644 index 000000000000..1c8f1bb25deb --- /dev/null +++ b/prdoc/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/pr_6305.prdoc new file mode 100644 index 000000000000..bfc6f06b19ec --- /dev/null +++ b/prdoc/pr_6305.prdoc @@ -0,0 +1,17 @@ +title: Remove `riscv` feature flag +doc: +- audience: Runtime Dev + description: Since https://github.com/paritytech/polkadot-sdk/pull/6266 we no longer + require a custom toolchain to build the `pallet-revive-fixtures`. Hence we no + longer have to guard the build behind a feature flag. +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 +- name: polkadot-sdk + bump: major 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_6314.prdoc b/prdoc/pr_6314.prdoc new file mode 100644 index 000000000000..2ebbc68158d5 --- /dev/null +++ b/prdoc/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/pr_6315.prdoc b/prdoc/pr_6315.prdoc new file mode 100644 index 000000000000..6fc070b43b35 --- /dev/null +++ b/prdoc/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/pr_6316.prdoc new file mode 100644 index 000000000000..00ad8699ff85 --- /dev/null +++ b/prdoc/pr_6316.prdoc @@ -0,0 +1,8 @@ +title: Migrate pallet-election-provider-multi-phase benchmark to v2 and improve doc +doc: +- audience: Runtime Dev + description: |- + Migrate pallet-election-provider-multi-phase benchmark to v2 and improve doc +crates: +- name: pallet-election-provider-multi-phase + bump: patch diff --git a/prdoc/pr_6317.prdoc b/prdoc/pr_6317.prdoc new file mode 100644 index 000000000000..4034ab3f3012 --- /dev/null +++ b/prdoc/pr_6317.prdoc @@ -0,0 +1,12 @@ +title: eth-rpc fixes +doc: +- audience: Runtime Dev + description: | + Various fixes for the release of eth-rpc & ah-westend-runtime: + - Bump asset-hub westend spec version + - Fix the status of the Receipt to properly report failed transactions + - Fix value conversion between native and eth decimal representation + +crates: +- name: asset-hub-westend-runtime + bump: patch diff --git a/prdoc/pr_6318.prdoc b/prdoc/pr_6318.prdoc new file mode 100644 index 000000000000..b44a982f5992 --- /dev/null +++ b/prdoc/pr_6318.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 claims + +doc: + - audience: Runtime Dev + description: | + Adds bounds on stored types for pallet claims. + Migrates benchmarking from v1 to v2 for pallet claims. + +crates: + - name: polkadot-runtime-common + bump: patch diff --git a/prdoc/pr_6323.prdoc b/prdoc/pr_6323.prdoc new file mode 100644 index 000000000000..ec632a14f946 --- /dev/null +++ b/prdoc/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/pr_6337.prdoc b/prdoc/pr_6337.prdoc new file mode 100644 index 000000000000..aeab61cdf933 --- /dev/null +++ b/prdoc/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/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_6353.prdoc b/prdoc/pr_6353.prdoc new file mode 100644 index 000000000000..8a5a152628a0 --- /dev/null +++ b/prdoc/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/pr_6357.prdoc b/prdoc/pr_6357.prdoc new file mode 100644 index 000000000000..b3155b1a6050 --- /dev/null +++ b/prdoc/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/pr_6360.prdoc b/prdoc/pr_6360.prdoc new file mode 100644 index 000000000000..270af29e37af --- /dev/null +++ b/prdoc/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/pr_6365.prdoc b/prdoc/pr_6365.prdoc new file mode 100644 index 000000000000..b99a7ae4035e --- /dev/null +++ b/prdoc/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/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_6373.prdoc b/prdoc/pr_6373.prdoc new file mode 100644 index 000000000000..04758d9dd41f --- /dev/null +++ b/prdoc/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/pr_6380.prdoc b/prdoc/pr_6380.prdoc new file mode 100644 index 000000000000..72853bcf230c --- /dev/null +++ b/prdoc/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/pr_6382.prdoc b/prdoc/pr_6382.prdoc new file mode 100644 index 000000000000..ac6821c1100a --- /dev/null +++ b/prdoc/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/pr_6384.prdoc b/prdoc/pr_6384.prdoc new file mode 100644 index 000000000000..2ea0bc1043c3 --- /dev/null +++ b/prdoc/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/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_6406.prdoc b/prdoc/pr_6406.prdoc new file mode 100644 index 000000000000..9da4462263b9 --- /dev/null +++ b/prdoc/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/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_6418.prdoc b/prdoc/pr_6418.prdoc new file mode 100644 index 000000000000..6696b54024b9 --- /dev/null +++ b/prdoc/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/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_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_6454.prdoc b/prdoc/pr_6454.prdoc new file mode 100644 index 000000000000..3fd3e39db604 --- /dev/null +++ b/prdoc/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/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_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_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_6484.prdoc b/prdoc/pr_6484.prdoc new file mode 100644 index 000000000000..c212692e6ab4 --- /dev/null +++ b/prdoc/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/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_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_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_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_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/scripts/generate-umbrella.py b/scripts/generate-umbrella.py index e1ef6de86f9c..8326909c3449 100644 --- a/scripts/generate-umbrella.py +++ b/scripts/generate-umbrella.py @@ -111,7 +111,6 @@ def main(path, version): "runtime": list([f"{d.name}" for d, _ in runtime_crates]), "node": ["std"] + list([f"{d.name}" for d, _ in std_crates]), "tuples-96": [], - "riscv": [], } manifest = { @@ -207,4 +206,3 @@ def parse_args(): if __name__ == "__main__": args = parse_args() main(args.sdk, args.version) - diff --git a/scripts/release/build-changelogs.sh b/scripts/release/build-changelogs.sh index d73f06c8cd6b..d1bbe136ad48 100755 --- a/scripts/release/build-changelogs.sh +++ b/scripts/release/build-changelogs.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash export PRODUCT=polkadot -export VERSION=${VERSION:-1.5.0} +export VERSION=${VERSION:-stable2409} export ENGINE=${ENGINE:-podman} export REF1=${REF1:-'HEAD'} export REF2=${REF2} @@ -66,33 +66,21 @@ echo "Changelog ready in $OUTPUT/relnote_commits.md" # Show the files tree -s -h -c $OUTPUT/ -ASSET_HUB_ROCOCO_DIGEST=${ASSET_HUB_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/asset-hub-rococo-srtool-digest.json"} ASSET_HUB_WESTEND_DIGEST=${ASSET_HUB_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/asset-hub-westend-srtool-digest.json"} -BRIDGE_HUB_ROCOCO_DIGEST=${BRIDGE_HUB_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/bridge-hub-rococo-srtool-digest.json"} BRIDGE_HUB_WESTEND_DIGEST=${BRIDGE_HUB_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/bridge-hub-westend-srtool-digest.json"} COLLECTIVES_WESTEND_DIGEST=${COLLECTIVES_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/collectives-westend-srtool-digest.json"} -CONTRACTS_ROCOCO_DIGEST=${CONTRACTS_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/contracts-rococo-srtool-digest.json"} -CORETIME_ROCOCO_DIGEST=${CORETIME_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/coretime-rococo-srtool-digest.json"} CORETIME_WESTEND_DIGEST=${CORETIME_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/coretime-westend-srtool-digest.json"} GLUTTON_WESTEND_DIGEST=${GLUTTON_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/glutton-westend-srtool-digest.json"} -PEOPLE_ROCOCO_DIGEST=${PEOPLE_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/people-rococo-srtool-digest.json"} PEOPLE_WESTEND_DIGEST=${PEOPLE_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/people-westend-srtool-digest.json"} -ROCOCO_DIGEST=${ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/rococo-srtool-digest.json"} WESTEND_DIGEST=${WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/westend-srtool-digest.json"} jq \ - --slurpfile srtool_asset_hub_rococo $ASSET_HUB_ROCOCO_DIGEST \ --slurpfile srtool_asset_hub_westend $ASSET_HUB_WESTEND_DIGEST \ - --slurpfile srtool_bridge_hub_rococo $BRIDGE_HUB_ROCOCO_DIGEST \ --slurpfile srtool_bridge_hub_westend $BRIDGE_HUB_WESTEND_DIGEST \ --slurpfile srtool_collectives_westend $COLLECTIVES_WESTEND_DIGEST \ - --slurpfile srtool_contracts_rococo $CONTRACTS_ROCOCO_DIGEST \ - --slurpfile srtool_coretime_rococo $CORETIME_ROCOCO_DIGEST\ --slurpfile srtool_coretime_westend $CORETIME_WESTEND_DIGEST \ --slurpfile srtool_glutton_westend $GLUTTON_WESTEND_DIGEST \ - --slurpfile srtool_people_rococ $PEOPLE_ROCOCO_DIGEST \ --slurpfile srtool_people_westend $PEOPLE_WESTEND_DIGEST \ - --slurpfile srtool_rococo $ROCOCO_DIGEST \ --slurpfile srtool_westend $WESTEND_DIGEST \ -n '{ srtool: [ @@ -102,13 +90,7 @@ jq \ { order: 13, name: "Westend Collectives", data: $srtool_collectives_westend[0] }, { order: 14, name: "Westend Coretime", data: $srtool_coretime_westend[0] }, { order: 15, name: "Westend Glutton", data: $srtool_glutton_westend[0] }, - { order: 16, name: "Westend People", data: $srtool_people_westend[0] }, - { order: 17, name: "Rococo", data: $srtool_rococo[0] }, - { order: 18, name: "Rococo AssetHub", data: $srtool_asset_hub_rococo[0] }, - { order: 19, name: "Rococo BridgeHub", data: $srtool_bridge_hub_rococo[0] }, - { order: 20, name: "Rococo Contracts", data: $srtool_contracts_rococo[0] }, - { order: 21, name: "Rococo Coretime", data: $srtool_coretime_rococo[0] }, - { order: 22, name: "Rococo People", data: $srtool_people_rococ[0] } + { order: 16, name: "Westend People", data: $srtool_people_westend[0] } ] }' > "$PROJECT_ROOT/scripts/release/context.json" RELEASE_DIR="$PROJECT_ROOT/scripts/release/" 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/scripts/release/templates/changelog.md.tera b/scripts/release/templates/changelog.md.tera index aaba761e8e47..8d17451c8d05 100644 --- a/scripts/release/templates/changelog.md.tera +++ b/scripts/release/templates/changelog.md.tera @@ -1,4 +1,4 @@ -## Changelog for `{{ env.PRODUCT | capitalize }} v{{ env.VERSION }}` +## Changelog for `{{ env.PRODUCT | capitalize }} {{ env.VERSION }}` {% for file in prdoc | sort(attribute="doc_filename.number") -%} {%- set author= file.content.author | default(value="n/a") -%} diff --git a/substrate/.maintain/frame-umbrella-weight-template.hbs b/substrate/.maintain/frame-umbrella-weight-template.hbs new file mode 100644 index 000000000000..b174823b3840 --- /dev/null +++ b/substrate/.maintain/frame-umbrella-weight-template.hbs @@ -0,0 +1,120 @@ +{{header}} +//! Autogenerated weights for `{{pallet}}` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` +//! WASM-EXECUTION: `{{cmd.wasm_execution}}`, CHAIN: `{{cmd.chain}}`, DB CACHE: `{{cmd.db_cache}}` + +// Executed Command: +{{#each args as |arg|}} +// {{arg}} +{{/each}} + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame::weights_prelude::*; + +/// Weight functions needed for `{{pallet}}`. +pub trait WeightInfo { + {{#each benchmarks as |benchmark|}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{c.name}}: u32, {{/each~}} + ) -> Weight; + {{/each}} +} + +/// Weights for `{{pallet}}` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +{{#if (or (eq pallet "frame_system") (eq pallet "frame_system_extensions"))}} +impl WeightInfo for SubstrateWeight { +{{else}} +impl WeightInfo for SubstrateWeight { +{{/if}} + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} diff --git a/substrate/.maintain/frame-weight-template.hbs b/substrate/.maintain/frame-weight-template.hbs index ecd384a51456..ec9eee205cee 100644 --- a/substrate/.maintain/frame-weight-template.hbs +++ b/substrate/.maintain/frame-weight-template.hbs @@ -33,7 +33,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..447f947107c1 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -15,6 +15,7 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-trait = { workspace = true } array-bytes = { workspace = true, default-features = true } clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } diff --git a/substrate/bin/node/bench/src/construct.rs b/substrate/bin/node/bench/src/construct.rs index 23d0a0cc1ee5..22129c6a1d69 100644 --- a/substrate/bin/node/bench/src/construct.rs +++ b/substrate/bin/node/bench/src/construct.rs @@ -24,18 +24,18 @@ //! 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; -use sp_runtime::{traits::NumberFor, OpaqueExtrinsic}; +use sp_runtime::OpaqueExtrinsic; use crate::{ common::SizeType, @@ -165,18 +165,18 @@ impl core::Benchmark for ConstructionBenchmark { #[derive(Clone, Debug)] pub struct PoolTransaction { - data: OpaqueExtrinsic, + data: Arc, hash: node_primitives::Hash, } impl From for PoolTransaction { fn from(e: OpaqueExtrinsic) -> Self { - PoolTransaction { data: e, hash: node_primitives::Hash::zero() } + PoolTransaction { data: Arc::from(e), hash: node_primitives::Hash::zero() } } } impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction { - type Transaction = OpaqueExtrinsic; + type Transaction = Arc; type Hash = node_primitives::Hash; fn data(&self) -> &Self::Transaction { @@ -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: NumberFor, - ) -> 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)) + _at: Self::Hash, + ) -> Box> + Send> { + Box::new(TransactionsIterator(self.0.clone().into_iter())) } fn ready(&self) -> Box> + Send> { @@ -305,4 +298,12 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { fn ready_transaction(&self, _hash: &TxHash) -> Option> { unimplemented!() } + + async fn ready_at_with_timeout( + &self, + _at: Self::Hash, + _timeout: std::time::Duration, + ) -> Box> + Send> { + unimplemented!() + } } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 6e734a723cd3..c179579c1885 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -46,9 +46,92 @@ futures = { workspace = true } log = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +subxt-signer = { workspace = true, features = ["unstable-eth"] } # The Polkadot-SDK: -polkadot-sdk = { features = ["node"], workspace = true, default-features = true } +polkadot-sdk = { features = [ + "fork-tree", + "frame-benchmarking-cli", + "frame-remote-externalities", + "frame-support-procedural-tools", + "generate-bags", + "mmr-gadget", + "mmr-rpc", + "pallet-transaction-payment-rpc", + "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", + "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", +], workspace = true, default-features = true } # Shared code between the staging node and kitchensink runtime: kitchensink-runtime = { workspace = true } @@ -71,6 +154,7 @@ 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: @@ -88,12 +172,7 @@ polkadot-sdk = { features = ["frame-benchmarking-cli", "sc-cli", "sc-storage-mon [features] default = ["cli"] -cli = [ - "clap", - "clap_complete", - "node-inspect", - "polkadot-sdk", -] +cli = ["clap", "clap_complete", "node-inspect", "polkadot-sdk"] runtime-benchmarks = [ "kitchensink-runtime/runtime-benchmarks", "node-inspect?/runtime-benchmarks", @@ -104,10 +183,6 @@ try-runtime = [ "polkadot-sdk/try-runtime", "substrate-cli-test-utils/try-runtime", ] -riscv = [ - "kitchensink-runtime/riscv", - "polkadot-sdk/riscv", -] [[bench]] name = "transaction_pool" diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index de883d1051f5..da82729dbec0 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -39,6 +39,7 @@ use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed} use sp_consensus::BlockOrigin; use sp_keyring::Sr25519Keyring; use sp_runtime::{ + generic, transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; @@ -120,11 +121,11 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - kitchensink_runtime::UncheckedExtrinsic { - signature: None, - function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), - } - .into() + let utx: kitchensink_runtime::UncheckedExtrinsic = generic::UncheckedExtrinsic::new_bare( + kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), + ) + .into(); + utx.into() } fn import_block(client: &FullClient, built: BuiltBlock) { diff --git a/substrate/bin/node/cli/benches/executor.rs b/substrate/bin/node/cli/benches/executor.rs index fa4da5c13d43..412b7f0ba0fc 100644 --- a/substrate/bin/node/cli/benches/executor.rs +++ b/substrate/bin/node/cli/benches/executor.rs @@ -31,7 +31,7 @@ use sp_core::{ storage::well_known_keys, traits::{CallContext, CodeExecutor, RuntimeCode}, }; -use sp_runtime::traits::BlakeTwo256; +use sp_runtime::{generic::ExtrinsicFormat, traits::BlakeTwo256}; use sp_state_machine::TestExternalities as CoreTestExternalities; use staging_node_cli::service::RuntimeExecutor; @@ -146,11 +146,11 @@ fn test_blocks( ) -> Vec<(Vec, Hash)> { let mut test_ext = new_test_ext(genesis_config); let mut block1_extrinsics = vec![CheckedExtrinsic { - signed: None, + format: ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: 0 }), }]; block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic { - signed: Some((alice(), signed_extra(i, 0))), + format: ExtrinsicFormat::Signed(alice(), tx_ext(i, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 1 * DOLLARS, diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index efec081427f4..c07cb3ec0d13 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -16,15 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use polkadot_sdk::*; -use std::time::Duration; - use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; use futures::{future, StreamExt}; use kitchensink_runtime::{constants::currency::*, BalancesCall, SudoCall}; use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool}; use node_primitives::AccountId; -use polkadot_sdk::sc_service::config::{ExecutorConfiguration, RpcConfiguration}; +use polkadot_sdk::{ + sc_service::config::{ExecutorConfiguration, RpcConfiguration}, + sc_transaction_pool_api::TransactionPool as _, + *, +}; use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, @@ -32,8 +33,7 @@ use sc_service::{ }, BasePath, Configuration, Role, }; -use sc_transaction_pool::PoolLimit; -use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus}; +use sc_transaction_pool_api::{TransactionSource, TransactionStatus}; use sp_core::{crypto::Pair, sr25519}; use sp_keyring::Sr25519Keyring; use sp_runtime::OpaqueExtrinsic; @@ -58,12 +58,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { impl_version: "1.0".into(), role: Role::Authority, tokio_handle: tokio_handle.clone(), - transaction_pool: TransactionPoolOptions { - ready: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, - future: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, - reject_future_transactions: false, - ban_time: Duration::from_secs(30 * 60), - }, + transaction_pool: TransactionPoolOptions::new_for_benchmarks(), network: network_config, keystore: KeystoreConfig::InMemory, database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index bc7821bfcf30..038aa2f60928 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -20,6 +20,7 @@ use polkadot_sdk::*; +use crate::chain_spec::{sc_service::Properties, sp_runtime::AccountId32}; use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, Block, MaxNominations, SessionKeys, StakerStatus, }; @@ -32,18 +33,17 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{crypto::UncheckedInto, sr25519, Pair, Public}; -use sp_mixnet::types::AuthorityId as MixnetId; -use sp_runtime::{ - traits::{IdentifyAccount, Verify}, - Perbill, +use sp_core::{ + crypto::{get_public_from_string_or_panic, UncheckedInto}, + sr25519, }; +use sp_keyring::Sr25519Keyring; +use sp_mixnet::types::AuthorityId as MixnetId; +use sp_runtime::Perbill; pub use kitchensink_runtime::RuntimeGenesisConfig; pub use node_primitives::{AccountId, Balance, Signature}; -type AccountPublic = ::Signer; - const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; const ENDOWMENT: Balance = 10_000_000 * DOLLARS; const STASH: Balance = ENDOWMENT / 1000; @@ -246,35 +246,20 @@ pub fn staging_testnet_config() -> ChainSpec { .build() } -/// Helper function to generate a crypto pair from seed. -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - /// Helper function to generate stash, controller and session key from seed. pub fn authority_keys_from_seed( seed: &str, ) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId, BeefyId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } @@ -307,22 +292,8 @@ fn configure_accounts( usize, Vec<(AccountId, AccountId, Balance, StakerStatus)>, ) { - let mut endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ] - }); + let mut endowed_accounts: Vec = + endowed_accounts.unwrap_or_else(default_endowed_accounts); // endow all authorities and nominators. initial_authorities .iter() @@ -429,7 +400,7 @@ pub fn testnet_genesis( "society": { "pot": 0 }, "assets": { // This asset is used by the NIS pallet as counterpart currency. - "assets": vec![(9, get_account_id_from_seed::("Alice"), true, 1)], + "assets": vec![(9, Sr25519Keyring::Alice.to_account_id(), true, 1)], }, "nominationPools": { "minCreateBond": 10 * DOLLARS, @@ -442,17 +413,41 @@ fn development_config_genesis_json() -> serde_json::Value { testnet_genesis( vec![authority_keys_from_seed("Alice")], vec![], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } +fn props() -> Properties { + let mut properties = Properties::new(); + properties.insert("tokenDecimals".to_string(), 12.into()); + 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.public_key().to_account_id().as_ref()); + account_id +} + +fn default_endowed_accounts() -> Vec { + Sr25519Keyring::well_known() + .map(|k| k.to_account_id()) + .chain([ + eth_account(subxt_signer::eth::dev::alith()), + eth_account(subxt_signer::eth::dev::baltathar()), + ]) + .collect() +} + /// Development config (single validator Alice). pub fn development_config() -> ChainSpec { ChainSpec::builder(wasm_binary_unwrap(), Default::default()) .with_name("Development") .with_id("dev") .with_chain_type(ChainType::Development) + .with_properties(props()) .with_genesis_config_patch(development_config_genesis_json()) .build() } @@ -461,7 +456,7 @@ fn local_testnet_genesis() -> serde_json::Value { testnet_genesis( vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], vec![], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -492,7 +487,7 @@ pub(crate) mod tests { .with_genesis_config_patch(testnet_genesis( vec![authority_keys_from_seed("Alice")], vec![], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, )) .build() diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs index c0dcacb2e4b4..1d7001a5dccf 100644 --- a/substrate/bin/node/cli/src/cli.rs +++ b/substrate/bin/node/cli/src/cli.rs @@ -59,6 +59,7 @@ pub enum Subcommand { Inspect(node_inspect::cli::InspectCmd), /// Sub-commands concerned with benchmarking. + /// /// The pallet benchmarking moved to the `pallet` sub-command. #[command(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), diff --git a/substrate/bin/node/cli/src/command.rs b/substrate/bin/node/cli/src/command.rs index 51fbf0904cf8..2910002e5b27 100644 --- a/substrate/bin/node/cli/src/command.rs +++ b/substrate/bin/node/cli/src/command.rs @@ -136,11 +136,12 @@ pub fn run() -> Result<()> { let ext_builder = RemarkBuilder::new(partial.client.clone()); cmd.run( - config, + config.chain_spec.name().into(), partial.client, inherent_benchmark_data()?, Vec::new(), &ext_builder, + false, ) }, BenchmarkCmd::Extrinsic(cmd) => { diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index 69e953f54e42..5cde85ae5790 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::{ @@ -42,6 +41,7 @@ use sc_network_sync::{strategy::warp::WarpSyncConfig, SyncingService}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_statement_store::Store as StatementStore; use sc_telemetry::{Telemetry, TelemetryWorker}; +use sc_transaction_pool::TransactionPoolHandle; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_api::ProvideRuntimeApi; use sp_core::crypto::Pair; @@ -80,7 +80,7 @@ type FullBeefyBlockImport = beefy::import::BeefyBlockImport< >; /// The transaction pool type definition. -pub type TransactionPool = sc_transaction_pool::FullPool; +pub type TransactionPool = sc_transaction_pool::TransactionPoolHandle; /// The minimum period of blocks on which justifications will be /// imported and generated. @@ -120,7 +120,7 @@ pub fn create_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let extra: kitchensink_runtime::SignedExtra = + let tx_ext: kitchensink_runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), @@ -142,7 +142,7 @@ pub fn create_extrinsic( let raw_payload = kitchensink_runtime::SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ( (), kitchensink_runtime::VERSION.spec_version, @@ -157,12 +157,13 @@ pub fn create_extrinsic( ); let signature = raw_payload.using_encoded(|e| sender.sign(e)); - kitchensink_runtime::UncheckedExtrinsic::new_signed( + generic::UncheckedExtrinsic::new_signed( function, sp_runtime::AccountId32::from(sender.public()).into(), kitchensink_runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) + .into() } /// Creates a new partial node. @@ -175,7 +176,7 @@ pub fn new_partial( FullBackend, FullSelectChain, sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ( impl Fn( sc_rpc::SubscriptionTaskExecutor, @@ -226,12 +227,15 @@ pub fn new_partial( let select_chain = sc_consensus::LongestChain::new(backend.clone()); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let (grandpa_block_import, grandpa_link) = grandpa::block_import( @@ -385,7 +389,7 @@ pub struct NewFullBase { /// The syncing service of the node. pub sync: Arc>, /// The transaction pool of the node. - pub transaction_pool: Arc, + pub transaction_pool: Arc>, /// The rpc handlers of the node. pub rpc_handlers: RpcHandlers, } @@ -415,10 +419,12 @@ pub fn new_full_base::Hash>>( let enable_offchain_worker = config.offchain_worker.enabled; let hwbench = (!disable_hardware_benchmarks) - .then_some(config.database.path().map(|database_path| { - let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) - })) + .then(|| { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(&database_path); + sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) + }) + }) .flatten(); let sc_service::PartialComponents { @@ -507,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, @@ -526,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, })?; @@ -783,9 +779,7 @@ pub fn new_full_base::Hash>>( ); if enable_offchain_worker { - task_manager.spawn_handle().spawn( - "offchain-workers-runner", - "offchain-work", + let offchain_workers = sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { runtime_api_provider: client.clone(), keystore: Some(keystore_container.keystore()), @@ -799,13 +793,14 @@ pub fn new_full_base::Hash>>( custom_extensions: move |_| { vec![Box::new(statement_store.clone().as_statement_store_ext()) as Box<_>] }, - }) - .run(client.clone(), task_manager.spawn_handle()) - .boxed(), + })?; + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-work", + offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(), ); } - network_starter.start_network(); Ok(NewFullBase { task_manager, client, @@ -862,24 +857,24 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, RuntimeCall, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, TxExtension, }; use node_primitives::{Block, DigestItem, Signature}; - use polkadot_sdk::*; + use polkadot_sdk::{sc_transaction_pool_api::MaintainedTransactionPool, *}; use sc_client_api::BlockBackend; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY}; use sc_consensus_epochs::descendent_query; use sc_keystore::LocalKeystore; use sc_service_test::TestNetNode; - use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool}; + use sc_transaction_pool_api::ChainEvent; use sp_consensus::{BlockOrigin, Environment, Proposer}; use sp_core::crypto::Pair; use sp_inherents::InherentDataProvider; use sp_keyring::AccountKeyring; use sp_keystore::KeystorePtr; use sp_runtime::{ - generic::{Digest, Era, SignedPayload}, + generic::{self, Digest, Era, SignedPayload}, key_types::BABE, traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify}, RuntimeAppPublic, @@ -985,7 +980,7 @@ mod tests { sc_consensus_babe::authorship::claim_slot(slot.into(), &epoch, &keystore) .map(|(digest, _)| digest) { - break (babe_pre_digest, epoch_descriptor) + break (babe_pre_digest, epoch_descriptor); } slot += 1; @@ -1066,7 +1061,7 @@ mod tests { pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None), ); let metadata_hash = frame_metadata_hash_extension::CheckMetadataHash::new(false); - let extra = ( + let tx_ext: TxExtension = ( check_non_zero_sender, check_spec_version, check_tx_version, @@ -1079,7 +1074,7 @@ mod tests { ); let raw_payload = SignedPayload::from_raw( function, - extra, + tx_ext, ( (), spec_version, @@ -1093,10 +1088,18 @@ mod tests { ), ); let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); - let (function, extra, _) = raw_payload.deconstruct(); + let (function, tx_ext, _) = raw_payload.deconstruct(); index += 1; - UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra) - .into() + let utx: kitchensink_runtime::UncheckedExtrinsic = + generic::UncheckedExtrinsic::new_signed( + function, + from.into(), + signature.into(), + tx_ext, + ) + .into(); + + utx.into() }, ); } diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index 037ddbb1e47b..8f1475fce4f8 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -17,11 +17,11 @@ use codec::{Decode, Encode, Joiner}; use frame_support::{ - dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, + dispatch::{DispatchClass, GetDispatchInfo}, traits::Currency, weights::Weight, }; -use frame_system::{self, AccountInfo, EventRecord, Phase}; +use frame_system::{self, AccountInfo, DispatchEventInfo, EventRecord, Phase}; use polkadot_sdk::*; use sp_core::{storage::well_known_keys, traits::Externalities}; use sp_runtime::{ @@ -59,17 +59,23 @@ pub fn bloaty_code_unwrap() -> &'static [u8] { /// Note that reads the multiplier from storage directly, hence to get the fee of `extrinsic` /// at block `n`, it must be called prior to executing block `n` to do the calculation with the /// correct multiplier. -fn transfer_fee(extrinsic: &E) -> Balance { - TransactionPayment::compute_fee( - extrinsic.encode().len() as u32, - &default_transfer_call().get_dispatch_info(), - 0, - ) +fn transfer_fee(extrinsic: &UncheckedExtrinsic) -> Balance { + let mut info = default_transfer_call().get_dispatch_info(); + info.extension_weight = extrinsic.0.extension_weight(); + TransactionPayment::compute_fee(extrinsic.encode().len() as u32, &info, 0) +} + +/// Default transfer fee, same as `transfer_fee`, but with a weight refund factored in. +fn transfer_fee_with_refund(extrinsic: &UncheckedExtrinsic, weight_refund: Weight) -> Balance { + let mut info = default_transfer_call().get_dispatch_info(); + info.extension_weight = extrinsic.0.extension_weight(); + let post_info = (Some(info.total_weight().saturating_sub(weight_refund)), info.pays_fee).into(); + TransactionPayment::compute_actual_fee(extrinsic.encode().len() as u32, &info, &post_info, 0) } fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), function: RuntimeCall::Balances(default_transfer_call()), }) } @@ -86,11 +92,11 @@ fn changes_trie_block() -> (Vec, Hash) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, @@ -113,11 +119,11 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, @@ -133,18 +139,18 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { block1.1, vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { - signed: Some((bob(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(bob(), tx_ext(0, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: alice().into(), value: 5 * DOLLARS, }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(1, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(1, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 15 * DOLLARS, @@ -168,11 +174,11 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(nonce, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(nonce, 0)), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; size] }), }, ], @@ -257,13 +263,14 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0; assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -297,13 +304,14 @@ fn successful_execution_with_foreign_code_gives_ok() { let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0; assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -316,15 +324,18 @@ fn full_native_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); + let extension_weight = xt().0.extension_weight(); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); - let transfer_weight = default_transfer_call().get_dispatch_info().weight.saturating_add( + let transfer_weight = default_transfer_call().get_dispatch_info().call_weight.saturating_add( ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic, ); let timestamp_weight = pallet_timestamp::Call::set:: { now: Default::default() } .get_dispatch_info() - .weight + .call_weight .saturating_add( ::BlockWeights::get() .get(DispatchClass::Mandatory) @@ -334,17 +345,17 @@ fn full_native_block_import_works() { executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); alice_last_known_balance = Balances::total_balance(&alice()); let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, - ..Default::default() + pays_fee: Default::default(), }, }), topics: vec![], @@ -370,21 +381,21 @@ fn full_native_block_import_works() { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), - amount: fees * 8 / 10, + amount: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { - value: fees * 8 / 10, + value: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { - amount: fees * 2 / 10, + amount: fees_after_refund * 2 / 10, }), topics: vec![], }, @@ -393,7 +404,7 @@ fn full_native_block_import_works() { event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), - actual_fee: fees, + actual_fee: fees_after_refund, tip: 0, }, ), @@ -402,7 +413,11 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + dispatch_info: DispatchEventInfo { + weight: transfer_weight + .saturating_add(extension_weight.saturating_sub(weight_refund)), + ..Default::default() + }, }), topics: vec![], }, @@ -412,15 +427,18 @@ fn full_native_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); let pot = t.execute_with(|| Treasury::pot()); + let extension_weight = xt().0.extension_weight(); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); t.execute_with(|| { assert_eq!( Balances::total_balance(&alice()), - alice_last_known_balance - 10 * DOLLARS - fees, + alice_last_known_balance - 10 * DOLLARS - fees_after_refund, ); - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees_after_refund); let events = vec![ EventRecord { phase: Phase::Initialization, @@ -433,10 +451,10 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(0), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, - ..Default::default() + pays_fee: Default::default(), }, }), topics: vec![], @@ -462,21 +480,21 @@ fn full_native_block_import_works() { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), - amount: fees * 8 / 10, + amount: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { - value: fees * 8 / 10, + value: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { - amount: fees - fees * 8 / 10, + amount: fees_after_refund - fees_after_refund * 8 / 10, }), topics: vec![], }, @@ -485,7 +503,7 @@ fn full_native_block_import_works() { event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: bob().into(), - actual_fee: fees, + actual_fee: fees_after_refund, tip: 0, }, ), @@ -494,7 +512,11 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + dispatch_info: DispatchEventInfo { + weight: transfer_weight + .saturating_add(extension_weight.saturating_sub(weight_refund)), + ..Default::default() + }, }), topics: vec![], }, @@ -519,21 +541,21 @@ fn full_native_block_import_works() { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), - amount: fees * 8 / 10, + amount: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { - value: fees * 8 / 10, + value: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { - amount: fees - fees * 8 / 10, + amount: fees_after_refund - fees_after_refund * 8 / 10, }), topics: vec![], }, @@ -542,7 +564,7 @@ fn full_native_block_import_works() { event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), - actual_fee: fees, + actual_fee: fees_after_refund, tip: 0, }, ), @@ -551,7 +573,11 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + dispatch_info: DispatchEventInfo { + weight: transfer_weight + .saturating_add(extension_weight.saturating_sub(weight_refund)), + ..Default::default() + }, }), topics: vec![], }, @@ -567,26 +593,28 @@ fn full_wasm_block_import_works() { let (block1, block2) = blocks(); let mut alice_last_known_balance: Balance = Default::default(); - let mut fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); alice_last_known_balance = Balances::total_balance(&alice()); }); - fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); t.execute_with(|| { assert_eq!( Balances::total_balance(&alice()), - alice_last_known_balance - 10 * DOLLARS - fees, + alice_last_known_balance - 10 * DOLLARS - fees_after_refund, ); - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees); + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees_after_refund); }); } @@ -700,11 +728,11 @@ fn deploying_wasm_contract_should_work() { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)), function: RuntimeCall::Contracts(pallet_contracts::Call::instantiate_with_code::< Runtime, > { @@ -717,7 +745,7 @@ fn deploying_wasm_contract_should_work() { }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(1, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)), function: RuntimeCall::Contracts(pallet_contracts::Call::call:: { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, @@ -828,7 +856,8 @@ fn successful_execution_gives_ok() { assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS); }); - let fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())) .0 @@ -839,7 +868,7 @@ fn successful_execution_gives_ok() { .expect("Extrinsic failed"); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index b49af4c1055c..da9d2662408e 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -55,11 +55,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)), function: RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: Box::new(RuntimeCall::RootTesting( pallet_root_testing::Call::fill_block { ratio: Perbill::from_percent(60) }, @@ -78,11 +78,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { block1.1, vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(1, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1] }), }, ], @@ -148,7 +148,7 @@ fn transaction_fee_is_correct() { let tip = 1_000_000; let xt = sign(CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, tip))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, tip)), function: RuntimeCall::Balances(default_transfer_call()), }); @@ -174,7 +174,9 @@ fn transaction_fee_is_correct() { let length_fee = TransactionByteFee::get() * (xt.clone().encode().len() as Balance); balance_alice -= length_fee; - let weight = default_transfer_call().get_dispatch_info().weight; + let mut info = default_transfer_call().get_dispatch_info(); + info.extension_weight = xt.0.extension_weight(); + let weight = info.total_weight(); let weight_fee = IdentityFee::::weight_to_fee(&weight); // we know that weight to fee multiplier is effect-less in block 1. diff --git a/substrate/bin/node/cli/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs index 18826e7e90a7..3672432ae342 100644 --- a/substrate/bin/node/cli/tests/submit_transaction.rs +++ b/substrate/bin/node/cli/tests/submit_transaction.rs @@ -23,6 +23,7 @@ use sp_application_crypto::AppCrypto; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; use sp_keyring::sr25519::Keyring::Alice; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; +use sp_runtime::generic; pub mod common; use self::common::*; @@ -44,10 +45,9 @@ fn should_submit_unsigned_transaction() { }; let call = pallet_im_online::Call::heartbeat { heartbeat: heartbeat_data, signature }; - SubmitTransaction::>::submit_unsigned_transaction( - call.into(), - ) - .unwrap(); + let xt = generic::UncheckedExtrinsic::new_bare(call.into()).into(); + SubmitTransaction::>::submit_transaction(xt) + .unwrap(); assert_eq!(state.read().transactions.len(), 1) }); @@ -131,7 +131,7 @@ fn should_submit_signed_twice_from_the_same_account() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.signature.unwrap().2; + let extra = tx.0.preamble.to_signed().unwrap().2; extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); @@ -180,7 +180,7 @@ fn should_submit_signed_twice_from_all_accounts() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.signature.unwrap().2; + let extra = tx.0.preamble.to_signed().unwrap().2; extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); @@ -237,7 +237,7 @@ fn submitted_transaction_should_be_valid() { let source = TransactionSource::External; let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap(); // add balance to the account - let author = extrinsic.signature.clone().unwrap().0; + let author = extrinsic.0.preamble.clone().to_signed().clone().unwrap().0; let address = Indices::lookup(author).unwrap(); let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; let account = frame_system::AccountInfo { providers: 1, data, ..Default::default() }; diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 6310e16d5a14..3ad6315561d0 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -27,6 +27,7 @@ scale-info = { features = ["derive", "serde"], workspace = true } static_assertions = { workspace = true, default-features = true } log = { workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } +sp-debug-derive = { workspace = true, features = ["force-debug"] } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } @@ -56,6 +57,7 @@ std = [ "primitive-types/std", "scale-info/std", "serde_json/std", + "sp-debug-derive/std", "substrate-wasm-builder", ] runtime-benchmarks = [ @@ -72,4 +74,3 @@ experimental = [ "pallet-example-tasks/experimental", ] metadata-hash = ["substrate-wasm-builder/metadata-hash"] -riscv = ["polkadot-sdk/riscv"] diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 43e7a766e0e8..2e096342451d 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -65,7 +65,7 @@ impl IdentityVerifier for AllianceIdentityVerifier { fn has_good_judgement(who: &AccountId) -> bool { use pallet_identity::{IdentityOf, Judgement}; IdentityOf::::get(who) - .map(|(registration, _)| registration.judgements) + .map(|registration| registration.judgements) .map_or(false, |judgements| { judgements .iter() diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index c81921f844bd..e68e04840776 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,7 +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; @@ -94,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::{ @@ -102,8 +111,8 @@ use sp_runtime::{ MaybeConvert, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perbill, Percent, Permill, Perquintill, - RuntimeDebug, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perbill, + Percent, Permill, Perquintill, RuntimeDebug, }; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; @@ -160,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 @@ -266,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; @@ -574,6 +613,7 @@ impl pallet_transaction_payment::Config for Runtime { MinimumMultiplier, MaximumMultiplier, >; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_asset_conversion_tx_payment::Config for Runtime { @@ -585,6 +625,9 @@ impl pallet_asset_conversion_tx_payment::Config for Runtime { AssetConversion, ResolveAssetTo, >; + type WeightInfo = pallet_asset_conversion_tx_payment::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } impl pallet_skip_feeless_payment::Config for Runtime { @@ -699,7 +742,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 { @@ -1255,14 +1298,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 { @@ -1270,11 +1314,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! { @@ -1410,7 +1454,7 @@ impl pallet_revive::Config for Runtime { type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = pallet_revive::weights::SubstrateWeight; type ChainExtension = (); - type AddressMapper = pallet_revive::DefaultAddressMapper; + type AddressMapper = pallet_revive::AccountId32Mapper; type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; type UnsafeUnstableInterface = ConstBool; @@ -1421,6 +1465,7 @@ impl pallet_revive::Config for Runtime { type Debug = (); type Xcm = (); type ChainId = ConstU64<420_420_420>; + type NativeToEthRatio = ConstU32<1_000_000>; // 10^(18 - 12) Eth is 10^18, Native is 10^12. } impl pallet_sudo::Config for Runtime { @@ -1438,16 +1483,29 @@ parameter_types! { pub const MaxPeerInHeartbeats: u32 = 10_000; } +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: RuntimeCall, extension: TxExtension) -> UncheckedExtrinsic { + generic::UncheckedExtrinsic::new_transaction(call, extension).into() + } +} + impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { let tip = 0; // take the biggest period possible. let period = @@ -1458,7 +1516,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let era = Era::mortal(period, current_block); - let extra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -1473,15 +1531,27 @@ where ), frame_metadata_hash_extension::CheckMetadataHash::new(false), ); - let raw_payload = SignedPayload::new(call, extra) + + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; let address = Indices::unlookup(account); - let (call, extra, _) = raw_payload.deconstruct(); - Some((call, (address, signature, extra))) + let (call, tx_ext, _) = raw_payload.deconstruct(); + let transaction = + generic::UncheckedExtrinsic::new_signed(call, address, signature, tx_ext).into(); + Some(transaction) + } +} + +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: RuntimeCall) -> UncheckedExtrinsic { + generic::UncheckedExtrinsic::new_bare(call).into() } } @@ -1490,12 +1560,12 @@ impl frame_system::offchain::SigningTypes for Runtime { type Signature = Signature; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; } impl pallet_im_online::Config for Runtime { @@ -1540,6 +1610,7 @@ parameter_types! { // information, already accounted for by the byte deposit pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 2 * DOLLARS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -1551,6 +1622,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -1562,6 +1634,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = pallet_identity::weights::SubstrateWeight; @@ -1990,6 +2063,30 @@ impl pallet_transaction_storage::Config for Runtime { ConstU32<{ pallet_transaction_storage::DEFAULT_MAX_TRANSACTION_SIZE }>; } +#[cfg(feature = "runtime-benchmarks")] +pub struct VerifySignatureBenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +impl pallet_verify_signature::BenchmarkHelper + for VerifySignatureBenchmarkHelper +{ + fn create_signature(_entropy: &[u8], msg: &[u8]) -> (MultiSignature, AccountId) { + use sp_io::crypto::{sr25519_generate, sr25519_sign}; + use sp_runtime::traits::IdentifyAccount; + let public = sr25519_generate(0.into(), None); + let who_account: AccountId = MultiSigner::Sr25519(public).into_account().into(); + let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &public, msg).unwrap()); + (signature, who_account) + } +} + +impl pallet_verify_signature::Config for Runtime { + type Signature = MultiSignature; + type AccountIdentifier = MultiSigner; + type WeightInfo = pallet_verify_signature::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = VerifySignatureBenchmarkHelper; +} + impl pallet_whitelist::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -2530,8 +2627,21 @@ mod runtime { #[runtime::pallet_index(80)] pub type Revive = pallet_revive::Pallet; + + #[runtime::pallet_index(81)] + pub type VerifySignature = pallet_verify_signature::Pallet; } +impl TryFrom for pallet_revive::Call { + type Error = (); + + fn try_from(value: RuntimeCall) -> Result { + match value { + RuntimeCall::Revive(call) => Ok(call), + _ => Err(()), + } + } +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. @@ -2542,12 +2652,12 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. +/// The TransactionExtension to the basic transaction logic. /// /// When you change this, you **MUST** modify [`sign`] in `bin/node/testing/src/keyring.rs`! /// /// [`sign`]: <../../testing/src/keyring.rs.html> -pub type SignedExtra = ( +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -2562,13 +2672,39 @@ pub type SignedExtra = ( frame_metadata_hash_extension::CheckMetadataHash, ); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct EthExtraImpl; + +impl EthExtra for EthExtraImpl { + type Config = Runtime; + type Extension = TxExtension; + + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::from(crate::generic::Era::Immortal), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from(tip, None) + .into(), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), + ) + } +} + /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + pallet_revive::evm::runtime::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -2624,6 +2760,62 @@ mod mmr { pub type Hashing = ::Hashing; } +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< + AccountId, + NativeOrWithId, + NativeOrWithId, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (NativeOrWithId, NativeOrWithId) { + (NativeOrWithId::WithId(seed), NativeOrWithId::WithId(seed)) + } + + fn setup_balances_and_pool(asset_id: NativeOrWithId, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + let NativeOrWithId::WithId(asset_idx) = asset_id.clone() else { unimplemented!() }; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_idx.into(), + account.clone().into(), /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = account.clone(); + let _ = Balances::deposit_creating(&lp_provider, ((u64::MAX as u128) * 100).into()); + assert_ok!(Assets::mint_into( + asset_idx.into(), + &lp_provider, + ((u64::MAX as u128) * 100).into() + )); + + let token_native = alloc::boxed::Box::new(NativeOrWithId::Native); + let token_second = alloc::boxed::Box::new(asset_id); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider.clone()), + token_native.clone(), + token_second.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider.clone()), + token_native, + token_second, + u64::MAX.into(), // 1 desired + u64::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider, + )); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benches { polkadot_sdk::frame_benchmarking::define_benchmarks!( @@ -2643,9 +2835,11 @@ mod benches { [pallet_contracts, Contracts] [pallet_revive, Revive] [pallet_core_fellowship, CoreFellowship] - [tasks_example, TasksExample] + [pallet_example_tasks, TasksExample] [pallet_democracy, Democracy] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetConversionTxPayment] + [pallet_transaction_payment, TransactionPayment] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] @@ -2679,6 +2873,7 @@ mod benches { [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] [pallet_tips, Tips] [pallet_transaction_storage, TransactionStorage] @@ -2694,6 +2889,7 @@ mod benches { [pallet_safe_mode, SafeMode] [pallet_example_mbm, PalletExampleMbms] [pallet_asset_conversion_ops, AssetConversionMigration] + [pallet_verify_signature, VerifySignature] ); } @@ -2810,15 +3006,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) } @@ -2826,7 +3022,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) } @@ -2838,9 +3034,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 { @@ -3004,8 +3204,49 @@ impl_runtime_apis! { } } - impl pallet_revive::ReviveApi for Runtime + impl pallet_revive::ReviveApi for Runtime { + 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: U256, + input: Vec, + gas_limit: Option, + storage_deposit_limit: Option, + ) -> pallet_revive::EthContractResult + { + 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); + let uxt: UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into(); + uxt.encoded_size() as u32 + }; + + Revive::bare_eth_transact( + origin, + dest, + value, + input, + gas_limit.unwrap_or(blockweights.max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + encoded_size, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + fn call( origin: AccountId, dest: H160, @@ -3013,7 +3254,7 @@ impl_runtime_apis! { gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, - ) -> pallet_revive::ContractExecResult { + ) -> pallet_revive::ContractResult { Revive::bare_call( RuntimeOrigin::signed(origin), dest, @@ -3034,7 +3275,7 @@ impl_runtime_apis! { code: pallet_revive::Code, data: Vec, salt: Option<[u8; 32]>, - ) -> pallet_revive::ContractInstantiateResult + ) -> pallet_revive::ContractResult { Revive::bare_instantiate( RuntimeOrigin::signed(origin), @@ -3361,6 +3602,7 @@ impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; @@ -3374,7 +3616,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; @@ -3385,6 +3627,7 @@ impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index a5cec856717f..16112386ad7c 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -28,6 +28,7 @@ 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-skip-feeless-payment = { workspace = true, default-features = true } diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 007d314684cf..35f041ef0445 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -47,10 +47,13 @@ use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy}; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_consensus::BlockOrigin; -use sp_core::{ed25519, sr25519, traits::SpawnNamed, Pair, Public}; +use sp_core::{ + crypto::get_public_from_string_or_panic, ed25519, sr25519, traits::SpawnNamed, Pair, +}; use sp_crypto_hashing::blake2_256; use sp_inherents::InherentData; use sp_runtime::{ + generic::{self, ExtrinsicFormat, Preamble, EXTRINSIC_FORMAT_VERSION}, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -288,17 +291,18 @@ impl<'a> Iterator for BlockContentIterator<'a> { } let sender = self.keyring.at(self.iteration); - let receiver = get_account_id_from_seed::(&format!( + let receiver = get_public_from_string_or_panic::(&format!( "random-user//{}", self.iteration - )); + )) + .into(); let signed = self.keyring.sign( CheckedExtrinsic { - signed: Some(( + format: ExtrinsicFormat::Signed( sender, - signed_extra(0, kitchensink_runtime::ExistentialDeposit::get() + 1), - )), + tx_ext(0, kitchensink_runtime::ExistentialDeposit::get() + 1), + ), function: match self.content.block_type { BlockType::RandomTransfersKeepAlive => RuntimeCall::Balances(BalancesCall::transfer_keep_alive { @@ -562,11 +566,11 @@ impl BenchKeyring { tx_version: u32, genesis_hash: [u8; 32], ) -> UncheckedExtrinsic { - match xt.signed { - Some((signed, extra)) => { + match xt.format { + ExtrinsicFormat::Signed(signed, tx_ext) => { let payload = ( xt.function, - extra.clone(), + tx_ext.clone(), spec_version, tx_version, genesis_hash, @@ -582,12 +586,26 @@ impl BenchKeyring { key.sign(b) } }); - UncheckedExtrinsic { - signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), + generic::UncheckedExtrinsic { + preamble: Preamble::Signed( + sp_runtime::MultiAddress::Id(signed), + signature, + tx_ext, + ), function: payload.0, } + .into() }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + ExtrinsicFormat::Bare => generic::UncheckedExtrinsic { + preamble: Preamble::Bare(EXTRINSIC_FORMAT_VERSION), + function: xt.function, + } + .into(), + ExtrinsicFormat::General(ext_version, tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(ext_version, tx_ext), + function: xt.function, + } + .into(), } } @@ -630,19 +648,6 @@ pub struct BenchContext { type AccountPublic = ::Signer; -fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - impl BenchContext { /// Import some block. pub fn import_block(&mut self, block: Block) { diff --git a/substrate/bin/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index eab088d9100e..e5b0299f01a8 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -19,58 +19,61 @@ //! Test accounts. use codec::Encode; -use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic}; -use node_cli::chain_spec::get_from_seed; +use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, TxExtension, UncheckedExtrinsic}; use node_primitives::{AccountId, Balance, Nonce}; -use sp_core::{ecdsa, ed25519, sr25519}; +use sp_core::{crypto::get_public_from_string_or_panic, ecdsa, ed25519, sr25519}; use sp_crypto_hashing::blake2_256; -use sp_keyring::AccountKeyring; -use sp_runtime::generic::Era; +use sp_keyring::Sr25519Keyring; +use sp_runtime::generic::{self, Era, ExtrinsicFormat, EXTRINSIC_FORMAT_VERSION}; /// Alice's account id. pub fn alice() -> AccountId { - AccountKeyring::Alice.into() + Sr25519Keyring::Alice.into() } /// Bob's account id. pub fn bob() -> AccountId { - AccountKeyring::Bob.into() + Sr25519Keyring::Bob.into() } /// Charlie's account id. pub fn charlie() -> AccountId { - AccountKeyring::Charlie.into() + Sr25519Keyring::Charlie.into() } /// Dave's account id. pub fn dave() -> AccountId { - AccountKeyring::Dave.into() + Sr25519Keyring::Dave.into() } /// Eve's account id. pub fn eve() -> AccountId { - AccountKeyring::Eve.into() + Sr25519Keyring::Eve.into() } /// Ferdie's account id. pub fn ferdie() -> AccountId { - AccountKeyring::Ferdie.into() + Sr25519Keyring::Ferdie.into() } /// Convert keyrings into `SessionKeys`. +/// +/// # Panics +/// +/// Function will panic when invalid string is provided. pub fn session_keys_from_seed(seed: &str) -> SessionKeys { SessionKeys { - grandpa: get_from_seed::(seed).into(), - babe: get_from_seed::(seed).into(), - im_online: get_from_seed::(seed).into(), - authority_discovery: get_from_seed::(seed).into(), - mixnet: get_from_seed::(seed).into(), - beefy: get_from_seed::(seed).into(), + grandpa: get_public_from_string_or_panic::(seed).into(), + babe: get_public_from_string_or_panic::(seed).into(), + im_online: get_public_from_string_or_panic::(seed).into(), + authority_discovery: get_public_from_string_or_panic::(seed).into(), + mixnet: get_public_from_string_or_panic::(seed).into(), + beefy: get_public_from_string_or_panic::(seed).into(), } } /// Returns transaction extra. -pub fn signed_extra(nonce: Nonce, extra_fee: Balance) -> SignedExtra { +pub fn tx_ext(nonce: Nonce, extra_fee: Balance) -> TxExtension { ( frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), @@ -94,18 +97,18 @@ pub fn sign( genesis_hash: [u8; 32], metadata_hash: Option<[u8; 32]>, ) -> UncheckedExtrinsic { - match xt.signed { - Some((signed, extra)) => { + match xt.format { + ExtrinsicFormat::Signed(signed, tx_ext) => { let payload = ( xt.function, - extra.clone(), + tx_ext.clone(), spec_version, tx_version, genesis_hash, genesis_hash, metadata_hash, ); - let key = AccountKeyring::from_account_id(&signed).unwrap(); + let key = Sr25519Keyring::from_account_id(&signed).unwrap(); let signature = payload .using_encoded(|b| { @@ -116,11 +119,25 @@ pub fn sign( } }) .into(); - UncheckedExtrinsic { - signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), + generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::Signed( + sp_runtime::MultiAddress::Id(signed), + signature, + tx_ext, + ), function: payload.0, } + .into() }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + ExtrinsicFormat::Bare => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::Bare(EXTRINSIC_FORMAT_VERSION), + function: xt.function, + } + .into(), + 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 f2fe8cb7e166..b71e935a918f 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -21,15 +21,28 @@ path = "bin/main.rs" name = "chain-spec-builder" [lib] -crate-type = ["rlib"] +# Docs tests are not needed since the code samples that would be executed +# are exercised already in the context of unit/integration tests, by virtue +# of using a combination of encapsulation in functions + `docify::export`. +# This is a practice we should use for new code samples if any. +doctest = false [dependencies] clap = { features = ["derive"], workspace = true } +docify = { workspace = true } log = { workspace = true, default-features = true } -sc-chain-spec = { features = ["clap"], 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 } sp-tracing = { workspace = true, default-features = true } [dev-dependencies] substrate-test-runtime = { workspace = true } +cmd_lib = { workspace = true } +docify = { workspace = true } + +[features] +# `cargo build --feature=generate-readme` updates the `README.md` file. +generate-readme = [] diff --git a/substrate/bin/utils/chain-spec-builder/README.docify.md b/substrate/bin/utils/chain-spec-builder/README.docify.md new file mode 100644 index 000000000000..75d05bccfe0d --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/README.docify.md @@ -0,0 +1,146 @@ +# Chain Spec Builder + +Substrate's chain spec builder utility. + +A chain-spec is short for `chain-specification`. See the [`sc-chain-spec`](https://crates.io/docs.rs/sc-chain-spec/latest/sc_chain_spec) +for more information. + +_Note:_ this binary is a more flexible alternative to the `build-spec` subcommand, contained in typical Substrate-based nodes. +This particular binary is capable of interacting with [`sp-genesis-builder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/index.html) +implementation of any provided runtime allowing to build chain-spec JSON files. + +See [`ChainSpecBuilderCmd`](https://docs.rs/staging-chain-spec-builder/6.0.0/staging_chain_spec_builder/enum.ChainSpecBuilderCmd.html) +for a list of available commands. + +## Installation + +```bash +cargo install staging-chain-spec-builder +``` + +_Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.io) under +[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict. + +## Usage + +Please note that below usage is backed by integration tests. The commands' examples are wrapped +around by the `bash!(...)` macro calls. + +### Generate chains-spec using default config from runtime + +Query the default genesis config from the provided runtime WASM blob and use it in the chain spec. + + + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime function is called. + +### Display the runtime's default `GenesisConfig` + + + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime function is called. + +### Display the `GenesisConfig` preset with given name + + + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime function is called. + +### List the names of `GenesisConfig` presets provided by runtime + + + +_Note:_ [`GenesisBuilder::preset_names`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names) +runtime function is called. + +### Generate chain spec using runtime provided genesis config preset + +Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain +version of chain spec: + + + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime functions are called. + +### Generate raw storage chain spec using genesis config patch + +Patch the runtime's default genesis config with provided `patch.json` and generate raw +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) +runtime functions are called. + +### Generate raw storage chain spec using full genesis config + +Build the chain spec using provided full genesis config json file. No defaults will be used: + + + +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. + +### Generate human readable chain spec using provided genesis config patch + + + +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), +[`ConvertToRawCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.ConvertToRawCmd.html), +[`UpdateCodeCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.UpdateCodeCmd.html). diff --git a/substrate/bin/utils/chain-spec-builder/README.md b/substrate/bin/utils/chain-spec-builder/README.md new file mode 100644 index 000000000000..a85b37826139 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/README.md @@ -0,0 +1,184 @@ +# Chain Spec Builder + +Substrate's chain spec builder utility. + +A chain-spec is short for `chain-specification`. See the [`sc-chain-spec`](https://crates.io/docs.rs/sc-chain-spec/latest/sc_chain_spec) +for more information. + +_Note:_ this binary is a more flexible alternative to the `build-spec` subcommand, contained in typical Substrate-based nodes. +This particular binary is capable of interacting with [`sp-genesis-builder`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/index.html) +implementation of any provided runtime allowing to build chain-spec JSON files. + +See [`ChainSpecBuilderCmd`](https://docs.rs/staging-chain-spec-builder/6.0.0/staging_chain_spec_builder/enum.ChainSpecBuilderCmd.html) +for a list of available commands. + +## Installation + +```bash +cargo install staging-chain-spec-builder +``` + +_Note:_ `chain-spec-builder` binary is published on [crates.io](https://crates.io) under +[`staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder) due to a name conflict. + +## Usage + +Please note that below usage is backed by integration tests. The commands' examples are wrapped +around by the `bash!(...)` macro calls. + +### Generate chains-spec using default config from runtime + +Query the default genesis config from the provided runtime WASM blob and use it in the chain spec. + +```rust,ignore +bash!( + chain-spec-builder -c "/dev/stdout" create -r $runtime_path default +) +``` + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime function is called. + +### Display the runtime's default `GenesisConfig` + +```rust,ignore +bash!( + chain-spec-builder display-preset -r $runtime_path +) +``` + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime function is called. + +### Display the `GenesisConfig` preset with given name + +```rust,ignore +fn cmd_display_preset(runtime_path: &str) -> String { + bash!( + chain-spec-builder display-preset -r $runtime_path -p "staging" + ) +} +``` + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime function is called. + +### List the names of `GenesisConfig` presets provided by runtime + +```rust,ignore +bash!( + chain-spec-builder list-presets -r $runtime_path +) +``` + +_Note:_ [`GenesisBuilder::preset_names`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names) +runtime function is called. + +### Generate chain spec using runtime provided genesis config preset + +Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain +version of chain spec: + +```rust,ignore +bash!( + chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging" +) +``` + +_Note:_ [`GenesisBuilder::get_preset`](https://docs.rs/sp-genesis-builder/latest/sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset) +runtime functions are called. + +### Generate raw storage chain spec using genesis config patch + +Patch the runtime's default genesis config with provided `patch.json` and generate raw +storage (`-s`) version of chain spec: + +```rust,ignore +bash!( + chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path patch "tests/input/patch.json" +) +``` + +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) +runtime functions are called. + +### Generate raw storage chain spec using full genesis config + +Build the chain spec using provided full genesis config json file. No defaults will be used: + +```rust,ignore +bash!( + chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path full "tests/input/full.json" +) +``` + +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. + +### Generate human readable chain spec using provided genesis config patch + +```rust,ignore +bash!( + chain-spec-builder -c "/dev/stdout" create -r $runtime_path patch "tests/input/patch.json" +) +``` + +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 +bash!( + chain-spec-builder -c "/dev/stdout" create -r $runtime_path full "tests/input/full.json" +) +``` + +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), +[`ConvertToRawCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.ConvertToRawCmd.html), +[`UpdateCodeCmd`](https://docs.rs/staging-chain-spec-builder/latest/staging_chain_spec_builder/struct.UpdateCodeCmd.html). diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 629edcf68568..73c2868b3312 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -15,107 +15,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - -//! Substrate's chain spec builder utility. -//! -//! A chain-spec is short for `chain-configuration`. See the [`sc-chain-spec`] for more information. -//! -//! Note that this binary is analogous to the `build-spec` subcommand, contained in typical -//! substrate-based nodes. This particular binary is capable of interacting with -//! [`sp-genesis-builder`] implementation of any provided runtime allowing to build chain-spec JSON -//! files. -//! -//! See [`ChainSpecBuilderCmd`] for a list of available commands. -//! -//! ## Typical use-cases. -//! ##### Generate chains-spec using default config from runtime. -//! -//! Query the default genesis config from the provided `runtime.wasm` and use it in the chain -//! spec. -//! ```bash -//! chain-spec-builder create -r runtime.wasm default -//! ``` -//! -//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] runtime function is -//! called. -//! -//! -//! ##### Display the runtime's default `GenesisConfig` -//! -//! Displays the content of the runtime's default `GenesisConfig` -//! ```bash -//! chain-spec-builder display-preset -r runtime.wasm -//! ``` -//! -//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] runtime function is called. -//! -//! ##### Display the `GenesisConfig` preset with given name -//! -//! Displays the content of the `GenesisConfig` preset for given name -//! ```bash -//! chain-spec-builder display-preset -r runtime.wasm -p "staging" -//! ``` -//! -//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] runtime function is called. -//! -//! ##### List the names of `GenesisConfig` presets provided by runtime. -//! -//! Displays the names of the presets of `GenesisConfigs` provided by runtime. -//! ```bash -//! chain-spec-builder list-presets -r runtime.wasm -//! ``` -//! -//! _Note:_ [`GenesisBuilder::preset_names`][sp-genesis-builder-list] runtime function is called. -//! -//! ##### Generate chain spec using runtime provided genesis config preset. -//! -//! Patch the runtime's default genesis config with the named preset provided by the runtime and generate the plain -//! version of chain spec: -//! ```bash -//! chain-spec-builder create -r runtime.wasm named-preset "staging" -//! ``` -//! -//! _Note:_ [`GenesisBuilder::get_preset`][sp-genesis-builder-get-preset] and [`GenesisBuilder::build_state`][sp-genesis-builder-build] runtime functions are called. -//! -//! ##### Generate raw storage chain spec using genesis config patch. -//! -//! Patch the runtime's default genesis config with provided `patch.json` and generate raw -//! storage (`-s`) version of chain spec: -//! ```bash -//! chain-spec-builder create -s -r runtime.wasm patch patch.json -//! ``` -//! -//! _Note:_ [`GenesisBuilder::build_state`][sp-genesis-builder-build] runtime function is called. -//! -//! ##### Generate raw storage chain spec using full genesis config. -//! -//! Build the chain spec using provided full genesis config json file. No defaults will be used: -//! ```bash -//! chain-spec-builder create -s -r runtime.wasm full full-genesis-config.json -//! ``` -//! -//! _Note_: [`GenesisBuilder::build_state`][sp-genesis-builder-build] runtime function is called. -//! -//! ##### Generate human readable chain spec using provided genesis config patch. -//! ```bash -//! chain-spec-builder create -r runtime.wasm patch patch.json -//! ``` -//! -//! ##### Generate human readable chain spec using provided full genesis config. -//! ```bash -//! chain-spec-builder create -r runtime.wasm full full-genesis-config.json -//! ``` -//! -//! ##### Extra tools. -//! The `chain-spec-builder` provides also some extra utilities: [`VerifyCmd`], [`ConvertToRawCmd`], -//! [`UpdateCodeCmd`]. -//! -//! [`sc-chain-spec`]: ../sc_chain_spec/index.html -//! [`node-cli`]: ../node_cli/index.html -//! [`sp-genesis-builder`]: ../sp_genesis_builder/index.html -//! [sp-genesis-builder-build]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.build_state -//! [sp-genesis-builder-list]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names -//! [sp-genesis-builder-get-preset]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset +#![doc = include_str!("../README.md")] +#[cfg(feature = "generate-readme")] +docify::compile_markdown!("README.docify.md", "README.md"); use clap::{Parser, Subcommand}; use sc_chain_spec::{ @@ -359,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) @@ -391,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/bin/utils/chain-spec-builder/tests/expected/create_with_full.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json index 6d127b6c0aca..10071670179a 100644 --- a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json @@ -16,9 +16,18 @@ "config": { "babe": { "authorities": [ - "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", - "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 1 + ], + [ + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + 1 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 1 + ] ], "epochConfig": { "allowed_slots": "PrimaryAndSecondaryVRFSlots", diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_default.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_default.json new file mode 100644 index 000000000000..203b6716cb26 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_default.json @@ -0,0 +1,36 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} \ No newline at end of file diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_plain.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_plain.json new file mode 100644 index 000000000000..26868c3241a1 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_plain.json @@ -0,0 +1,66 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "config": { + "babe": { + "authorities": [ + [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + 1 + ], + [ + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + 1 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 1 + ] + ], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 2, + 4 + ] + } + }, + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 2000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 2000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ] + }, + "system": {} + } + } + } +} \ No newline at end of file diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_raw.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_raw.json new file mode 100644 index 000000000000..523a266fc439 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_full_raw.json @@ -0,0 +1,39 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0100000000000000186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e0100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01000000000000001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0100000000000000186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e0100000000000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0200000000000000040000000000000002", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x000000000000000000000000010000000000000000008d49fd1a07000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x000000000000000000000000010000000000000000008d49fd1a07000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0080faca73f91f00" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_named_preset_staging.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_named_preset_staging.json new file mode 100644 index 000000000000..5cf51554b2cb --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_named_preset_staging.json @@ -0,0 +1,39 @@ +{ + "bootNodes": [], + "chainType": "Live", + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "patch": { + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" + ] + } + } + } + }, + "id": "custom", + "name": "Custom", + "para_id": 1000, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "protocolId": null, + "relay_chain": "dev", + "telemetryEndpoints": null +} \ No newline at end of file diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_plain.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_plain.json new file mode 100644 index 000000000000..b243534c0d61 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_plain.json @@ -0,0 +1,42 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "patch": { + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ] + } + } + } + } +} \ No newline at end of file diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_raw.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_raw.json new file mode 100644 index 000000000000..c4ac1cbe8ea1 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/create_with_patch_raw.json @@ -0,0 +1,37 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00806d8176de1800" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset.json new file mode 100644 index 000000000000..6aa6799af771 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset.json @@ -0,0 +1 @@ +{"babe":{"authorities":[],"epochConfig":{"allowed_slots":"PrimaryAndSecondaryVRFSlots","c":[1,4]}},"balances":{"balances":[]},"substrateTest":{"authorities":[]},"system":{}} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset_staging.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset_staging.json new file mode 100644 index 000000000000..b0c8e40c23a9 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/display_preset_staging.json @@ -0,0 +1 @@ +{"balances":{"balances":[["5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",1000000000000000],["5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y",1000000000000000]]},"substrateTest":{"authorities":["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY","5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"]}} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/doc/list_presets.json b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/list_presets.json new file mode 100644 index 000000000000..882462391888 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/doc/list_presets.json @@ -0,0 +1 @@ +{"presets":["foobar","staging"]} diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/full.json b/substrate/bin/utils/chain-spec-builder/tests/input/full.json index f05e3505a2bb..e34aede52cbe 100644 --- a/substrate/bin/utils/chain-spec-builder/tests/input/full.json +++ b/substrate/bin/utils/chain-spec-builder/tests/input/full.json @@ -1,9 +1,9 @@ { "babe": { "authorities": [ - "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", - "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1], + ["5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", 1], + ["5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", 1] ], "epochConfig": { "allowed_slots": "PrimaryAndSecondaryVRFSlots", diff --git a/substrate/bin/utils/chain-spec-builder/tests/test.rs b/substrate/bin/utils/chain-spec-builder/tests/test.rs index f553f05f20a0..5ac687d75fd4 100644 --- a/substrate/bin/utils/chain-spec-builder/tests/test.rs +++ b/substrate/bin/utils/chain-spec-builder/tests/test.rs @@ -19,7 +19,10 @@ use std::fs::File; use clap::Parser; + +use cmd_lib::spawn_with_output; use sc_chain_spec::update_code_in_json_chain_spec; +use serde_json::{from_reader, from_str, Value}; use staging_chain_spec_builder::ChainSpecBuilder; // note: the runtime path will not be read, runtime code will be set directly, to avoid hassle with @@ -28,6 +31,44 @@ const DUMMY_PATH: &str = "fake-runtime-path"; const OUTPUT_FILE: &str = "/tmp/chain_spec_builder.test_output_file.json"; +// Used for running commands visually pleasing in doc tests. +macro_rules! bash( + ( chain-spec-builder $($a:tt)* ) => {{ + let bin_path = env!("CARGO_BIN_EXE_chain-spec-builder"); + spawn_with_output!( + $bin_path $($a)* + ) + .expect("a process running. qed") + .wait_with_output() + .expect("to get output. qed.") + }} +); + +// Used specifically in docs tests. +fn doc_assert(output: String, expected_output_path: &str, remove_code: bool) { + let expected: Value = + from_reader(File::open(expected_output_path).unwrap()).expect("a valid JSON. qed."); + let output = if remove_code { + let mut output: Value = from_str(output.as_str()).expect("a valid JSON. qed."); + // Remove code sections gracefully for both `plain` & `raw`. + output + .get_mut("genesis") + .and_then(|inner| inner.get_mut("runtimeGenesis")) + .and_then(|inner| inner.as_object_mut()) + .and_then(|inner| inner.remove("code")); + output + .get_mut("genesis") + .and_then(|inner| inner.get_mut("raw")) + .and_then(|inner| inner.get_mut("top")) + .and_then(|inner| inner.as_object_mut()) + .and_then(|inner| inner.remove("0x3a636f6465")); + output + } else { + from_str::(output.as_str()).expect("a valid JSON. qed.") + }; + assert_eq!(output, expected); +} + /// Asserts that the JSON in output file matches the JSON in expected file. /// /// This helper function reads the JSON content from the file at `OUTPUT_FILE + suffix` path. If the @@ -192,3 +233,165 @@ fn test_add_code_substitute() { builder.run().unwrap(); assert_output_eq_expected(true, SUFFIX, "tests/expected/add_code_substitute.json"); } + +#[docify::export_content] +fn cmd_create_default(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c "/dev/stdout" create -r $runtime_path default + ) +} + +#[test] +fn create_default() { + doc_assert( + cmd_create_default( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/create_default.json", + true, + ); +} + +#[docify::export_content] +fn cmd_display_default_preset(runtime_path: &str) -> String { + bash!( + chain-spec-builder display-preset -r $runtime_path + ) +} + +#[test] +fn display_default_preset() { + doc_assert( + cmd_display_default_preset( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed."), + ), + "tests/expected/doc/display_preset.json", + false, + ); +} + +#[docify::export] +fn cmd_display_preset(runtime_path: &str) -> String { + bash!( + chain-spec-builder display-preset -r $runtime_path -p "staging" + ) +} + +#[test] +fn display_preset() { + doc_assert( + cmd_display_preset( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/display_preset_staging.json", + false, + ); +} + +#[docify::export_content] +fn cmd_list_presets(runtime_path: &str) -> String { + bash!( + chain-spec-builder list-presets -r $runtime_path + ) +} + +#[test] +fn list_presets() { + doc_assert( + cmd_list_presets( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/list_presets.json", + false, + ); +} + +#[docify::export_content] +fn cmd_create_with_named_preset(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c "/dev/stdout" create --relay-chain "dev" --para-id 1000 -r $runtime_path named-preset "staging" + ) +} + +#[test] +fn create_with_named_preset() { + doc_assert( + cmd_create_with_named_preset( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/create_with_named_preset_staging.json", + true, + ) +} + +#[docify::export_content] +fn cmd_create_with_patch_raw(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path patch "tests/input/patch.json" + ) +} + +#[test] +fn create_with_patch_raw() { + doc_assert( + cmd_create_with_patch_raw( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/create_with_patch_raw.json", + true, + ); +} + +#[docify::export_content] +fn cmd_create_with_patch_plain(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c "/dev/stdout" create -r $runtime_path patch "tests/input/patch.json" + ) +} + +#[test] +fn create_with_patch_plain() { + doc_assert( + cmd_create_with_patch_plain( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/create_with_patch_plain.json", + true, + ); +} + +#[docify::export_content] +fn cmd_create_full_plain(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c "/dev/stdout" create -r $runtime_path full "tests/input/full.json" + ) +} + +#[test] +fn create_full_plain() { + doc_assert( + cmd_create_full_plain( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/create_full_plain.json", + true, + ); +} + +#[docify::export_content] +fn cmd_create_full_raw(runtime_path: &str) -> String { + bash!( + chain-spec-builder -c "/dev/stdout" create -s -r $runtime_path full "tests/input/full.json" + ) +} + +#[test] +fn create_full_raw() { + doc_assert( + cmd_create_full_raw( + substrate_test_runtime::WASM_BINARY_PATH.expect("to be a valid path. qed"), + ), + "tests/expected/doc/create_full_raw.json", + true, + ); +} diff --git a/substrate/client/api/src/notifications/tests.rs b/substrate/client/api/src/notifications/tests.rs index fba829b1cf90..9ad7973514b2 100644 --- a/substrate/client/api/src/notifications/tests.rs +++ b/substrate/client/api/src/notifications/tests.rs @@ -18,7 +18,7 @@ use super::*; -use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; +use sp_runtime::testing::{Block as RawBlock, TestXt, H256 as Hash}; use std::iter::{empty, Empty}; type TestChangeSet = ( @@ -50,7 +50,7 @@ impl PartialEq for StorageChangeSet { } } -type Block = RawBlock>; +type Block = RawBlock>; #[test] fn triggering_change_should_notify_wildcard_listeners() { diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 09381ec6b553..fc88d07ef936 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -24,7 +24,6 @@ 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 } 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..ba82910efcdf 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() { @@ -646,7 +682,7 @@ where async fn handle_put_record_requested( &mut self, - record_key: KademliaKey, + record_key: Key, record_value: Vec, publisher: Option, expires: Option, @@ -907,7 +943,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 +982,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..6c3a3b56b1cb 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(); @@ -1018,7 +1020,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 +1058,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 527a3d12d9e7..79e6fddae99f 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -25,7 +25,6 @@ use futures::{ channel::oneshot, future, future::{Future, FutureExt}, - select, }; use log::{debug, error, info, trace, warn}; use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder}; @@ -416,26 +415,13 @@ where let mut skipped = 0; let mut unqueue_invalid = Vec::new(); - let mut t1 = self.transaction_pool.ready_at(self.parent_number).fuse(); - let mut t2 = - futures_timer::Delay::new(deadline.saturating_duration_since((self.now)()) / 8).fuse(); - - let mut pending_iterator = select! { - res = t1 => res, - _ = t2 => { - warn!(target: LOG_TARGET, - "Timeout fired waiting for transaction pool at block #{}. \ - Proceeding with production.", - self.parent_number, - ); - self.transaction_pool.ready() - }, - }; + let delay = deadline.saturating_duration_since((self.now)()) / 8; + let mut pending_iterator = + self.transaction_pool.ready_at_with_timeout(self.parent_hash, delay).await; let block_size_limit = block_size_limit.unwrap_or(self.default_block_size_limit); - debug!(target: LOG_TARGET, "Attempting to push transactions from the pool."); - debug!(target: LOG_TARGET, "Pool status: {:?}", self.transaction_pool.status()); + debug!(target: LOG_TARGET, "Attempting to push transactions from the pool at {:?}.", self.parent_hash); let mut transaction_pushed = false; let end_reason = loop { @@ -460,7 +446,7 @@ where break EndProposingReason::HitDeadline } - let pending_tx_data = pending_tx.data().clone(); + let pending_tx_data = (**pending_tx.data()).clone(); let pending_tx_hash = pending_tx.hash().clone(); let block_size = @@ -524,7 +510,7 @@ where pending_iterator.report_invalid(&pending_tx); debug!( target: LOG_TARGET, - "[{:?}] Invalid transaction: {}", pending_tx_hash, e + "[{:?}] Invalid transaction: {} at: {}", pending_tx_hash, e, self.parent_hash ); unqueue_invalid.push(pending_tx_hash); }, @@ -577,13 +563,25 @@ where ) }; - info!( - "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; {extrinsics_summary}", - block.header().number(), - block_took.as_millis(), - ::Hash::from(block.header().hash()), - block.header().parent_hash(), - ); + if log::log_enabled!(log::Level::Info) { + info!( + "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; extrinsics_count: {}", + block.header().number(), + block_took.as_millis(), + ::Hash::from(block.header().hash()), + block.header().parent_hash(), + extrinsics.len() + ) + } else if log::log_enabled!(log::Level::Debug) { + debug!( + "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; {extrinsics_summary}", + block.header().number(), + block_took.as_millis(), + ::Hash::from(block.header().hash()), + block.header().parent_hash(), + ); + } + telemetry!( self.telemetry; CONSENSUS_INFO; @@ -643,22 +641,20 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let hashof0 = client.info().genesis_hash; block_on(txpool.submit_at(hashof0, SOURCE, vec![extrinsic(0), extrinsic(1)])).unwrap(); block_on( txpool.maintain(chain_event( - client - .expect_header(client.info().genesis_hash) - .expect("there should be header"), + client.expect_header(hashof0).expect("there should be header"), )), ); @@ -698,13 +694,13 @@ mod tests { fn should_not_panic_when_deadline_is_reached() { let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let mut proposer_factory = ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None); @@ -735,13 +731,13 @@ mod tests { let (client, backend) = TestClientBuilder::new().build_with_backend(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().best_hash; @@ -791,13 +787,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let medium = |nonce| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(MEDIUM)) @@ -871,27 +867,27 @@ mod tests { // let's create one block and import it let block = propose_block(&client, 0, 2, 7); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 5); // now let's make sure that we can still make some progress let block = propose_block(&client, 1, 1, 5); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 4); // again let's make sure that we can still make some progress let block = propose_block(&client, 2, 1, 4); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 3); // again let's make sure that we can still make some progress let block = propose_block(&client, 3, 1, 3); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 2); // again let's make sure that we can still make some progress let block = propose_block(&client, 4, 2, 2); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 0); } @@ -899,13 +895,13 @@ mod tests { fn should_cease_building_block_when_block_limit_is_reached() { let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().genesis_hash; let genesis_header = client.expect_header(genesis_hash).expect("there should be header"); @@ -1004,13 +1000,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().genesis_hash; let tiny = |nonce| { @@ -1073,13 +1069,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().genesis_hash; let tiny = |who| { diff --git a/substrate/client/basic-authorship/src/lib.rs b/substrate/client/basic-authorship/src/lib.rs index 8f47c2ea00e6..adea7a3571dd 100644 --- a/substrate/client/basic-authorship/src/lib.rs +++ b/substrate/client/basic-authorship/src/lib.rs @@ -32,13 +32,13 @@ //! # use sc_transaction_pool::{BasicPool, FullChainApi}; //! # let client = Arc::new(substrate_test_runtime_client::new()); //! # let spawner = sp_core::testing::TaskExecutor::new(); -//! # let txpool = BasicPool::new_full( +//! # let txpool = Arc::from(BasicPool::new_full( //! # Default::default(), //! # true.into(), //! # None, //! # spawner.clone(), //! # client.clone(), -//! # ); +//! # )); //! // The first step is to create a `ProposerFactory`. //! let mut proposer_factory = ProposerFactory::new( //! spawner, diff --git a/substrate/client/chain-spec/src/genesis_block.rs b/substrate/client/chain-spec/src/genesis_block.rs index 3c7b9f64dcd6..3c5bf47c3fe8 100644 --- a/substrate/client/chain-spec/src/genesis_block.rs +++ b/substrate/client/chain-spec/src/genesis_block.rs @@ -108,6 +108,16 @@ impl, E: RuntimeVersionOf> GenesisBlockBuilder< ) -> sp_blockchain::Result { let genesis_storage = build_genesis_storage.build_storage().map_err(sp_blockchain::Error::Storage)?; + Self::new_with_storage(genesis_storage, commit_genesis_state, backend, executor) + } + + /// Constructs a new instance of [`GenesisBlockBuilder`] using provided storage. + pub fn new_with_storage( + genesis_storage: Storage, + commit_genesis_state: bool, + backend: Arc, + executor: E, + ) -> sp_blockchain::Result { Ok(Self { genesis_storage, commit_genesis_state, 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 b7d29aebc3d7..f0b9f8f9b905 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -43,6 +43,7 @@ sc-network = { workspace = true, default-features = true } sc-service = { workspace = true } sc-telemetry = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } 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/transaction_pool_params.rs b/substrate/client/cli/src/params/transaction_pool_params.rs index 48b2e5b1572b..9cf738f58b6b 100644 --- a/substrate/client/cli/src/params/transaction_pool_params.rs +++ b/substrate/client/cli/src/params/transaction_pool_params.rs @@ -16,8 +16,28 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clap::Args; -use sc_service::config::TransactionPoolOptions; +use clap::{Args, ValueEnum}; +use sc_transaction_pool::TransactionPoolOptions; + +/// Type of transaction pool to be used +#[derive(Debug, Clone, Copy, ValueEnum)] +#[value(rename_all = "kebab-case")] +pub enum TransactionPoolType { + /// Uses a legacy, single-state transaction pool. + SingleState, + /// Uses a fork-aware transaction pool. + ForkAware, +} + +impl Into for TransactionPoolType { + fn into(self) -> sc_transaction_pool::TransactionPoolType { + match self { + TransactionPoolType::SingleState => + sc_transaction_pool::TransactionPoolType::SingleState, + TransactionPoolType::ForkAware => sc_transaction_pool::TransactionPoolType::ForkAware, + } + } +} /// Parameters used to create the pool configuration. #[derive(Debug, Clone, Args)] @@ -35,30 +55,21 @@ pub struct TransactionPoolParams { /// If it is considered invalid. Defaults to 1800s. #[arg(long, value_name = "SECONDS")] pub tx_ban_seconds: Option, + + /// The type of transaction pool to be instantiated. + #[arg(long, value_enum, default_value_t = TransactionPoolType::SingleState)] + pub pool_type: TransactionPoolType, } impl TransactionPoolParams { /// Fill the given `PoolConfiguration` by looking at the cli parameters. pub fn transaction_pool(&self, is_dev: bool) -> TransactionPoolOptions { - let mut opts = TransactionPoolOptions::default(); - - // ready queue - opts.ready.count = self.pool_limit; - opts.ready.total_bytes = self.pool_kbytes * 1024; - - // future queue - let factor = 10; - opts.future.count = self.pool_limit / factor; - opts.future.total_bytes = self.pool_kbytes * 1024 / factor; - - opts.ban_time = if let Some(ban_seconds) = self.tx_ban_seconds { - std::time::Duration::from_secs(ban_seconds) - } else if is_dev { - std::time::Duration::from_secs(0) - } else { - std::time::Duration::from_secs(30 * 60) - }; - - opts + TransactionPoolOptions::new_with_params( + self.pool_limit, + self.pool_kbytes * 1024, + self.tx_ban_seconds, + self.pool_type.into(), + is_dev, + ) } } diff --git a/substrate/client/cli/src/signals.rs b/substrate/client/cli/src/signals.rs index 4b6a6f957a76..64cae03de7ac 100644 --- a/substrate/client/cli/src/signals.rs +++ b/substrate/client/cli/src/signals.rs @@ -89,4 +89,19 @@ impl Signals { Ok(()) } + + /// Execute the future task and returns it's value if it completes before the signal. + pub async fn try_until_signal(self, func: F) -> Result + where + F: Future + future::FusedFuture, + { + let signals = self.future().fuse(); + + pin_mut!(func, signals); + + select! { + s = signals => Err(s), + res = func => Ok(res), + } + } } diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index 57ee706a04f6..aa54da2a4434 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -108,7 +108,8 @@ pub(super) fn secondary_slot_author( return None } - let rand = U256::from((randomness, slot).using_encoded(sp_crypto_hashing::blake2_256)); + let rand = + U256::from_big_endian(&(randomness, slot).using_encoded(sp_crypto_hashing::blake2_256)); let authorities_len = U256::from(authorities.len()); let idx = rand % authorities_len; @@ -271,7 +272,9 @@ fn claim_primary_slot( #[cfg(test)] mod tests { use super::*; - use sp_consensus_babe::{AllowedSlots, AuthorityId, BabeEpochConfiguration, Epoch}; + use sp_consensus_babe::{ + AllowedSlots, AuthorityId, BabeEpochConfiguration, Epoch, RANDOMNESS_LENGTH, + }; use sp_core::{crypto::Pair as _, sr25519::Pair}; use sp_keystore::testing::MemoryKeystore; @@ -305,4 +308,18 @@ mod tests { epoch.authorities.push((valid_public_key.into(), 10)); assert_eq!(claim_slot(10.into(), &epoch, &keystore).unwrap().1, valid_public_key.into()); } + + #[test] + fn secondary_slot_author_selection_works() { + let authorities = (0..1000) + .map(|i| (AuthorityId::from(Pair::generate().0.public()), i)) + .collect::>(); + + let randomness = [3; RANDOMNESS_LENGTH]; + + assert_eq!( + *secondary_slot_author(100.into(), &authorities, randomness).unwrap(), + authorities[167].0 + ); + } } 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/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/benches/state_access.rs b/substrate/client/db/benches/state_access.rs index e47559e710df..7ea8e7080184 100644 --- a/substrate/client/db/benches/state_access.rs +++ b/substrate/client/db/benches/state_access.rs @@ -22,12 +22,12 @@ use sc_client_api::{Backend as _, BlockImportOperation, NewBlockState, StateBack use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sp_core::H256; use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, Header}, + testing::{Block as RawBlock, Header, MockCallU64, TestXt}, StateVersion, Storage, }; use tempfile::TempDir; -pub(crate) type Block = RawBlock>; +pub(crate) type Block = RawBlock>; fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 { let mut op = db.begin_operation().unwrap(); diff --git a/substrate/client/db/src/lib.rs b/substrate/client/db/src/lib.rs index 72a9c7deaeb8..b505d167ad4c 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -1497,6 +1497,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)?; @@ -1688,6 +1689,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 { @@ -1706,43 +1724,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:?}"); + } } } @@ -2617,7 +2657,7 @@ pub(crate) mod tests { use sp_blockchain::{lowest_common_ancestor, tree_route}; use sp_core::H256; use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, Header}, + testing::{Block as RawBlock, Header, MockCallU64, TestXt}, traits::{BlakeTwo256, Hash}, ConsensusEngineId, StateVersion, }; @@ -2625,7 +2665,8 @@ pub(crate) mod tests { const CONS0_ENGINE_ID: ConsensusEngineId = *b"CON0"; const CONS1_ENGINE_ID: ConsensusEngineId = *b"CON1"; - pub(crate) type Block = RawBlock>; + type UncheckedXt = TestXt; + pub(crate) type Block = RawBlock; pub fn insert_header( backend: &Backend, @@ -2644,7 +2685,7 @@ pub(crate) mod tests { parent_hash: H256, _changes: Option, Vec)>>, extrinsics_root: H256, - body: Vec>, + body: Vec, transaction_index: Option>, ) -> Result { use sp_runtime::testing::Digest; @@ -3730,7 +3771,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3752,11 +3793,20 @@ pub(crate) mod tests { assert_eq!(None, bc.body(blocks[0]).unwrap()); assert_eq!(None, bc.body(blocks[1]).unwrap()); assert_eq!(None, bc.body(blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); } else { for i in 0..5 { - assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]), + bc.body(blocks[i]).unwrap() + ); } } } @@ -3780,7 +3830,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3789,16 +3839,26 @@ pub(crate) mod tests { } // insert a fork at block 2 - let fork_hash_root = - insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) - .unwrap(); + let fork_hash_root = insert_block( + &backend, + 2, + blocks[1], + None, + H256::random(), + vec![UncheckedXt::new_transaction(2.into(), ())], + None, + ) + .unwrap(); insert_block( &backend, 3, fork_hash_root, None, H256::random(), - vec![3.into(), 11.into()], + vec![ + UncheckedXt::new_transaction(3.into(), ()), + UncheckedXt::new_transaction(11.into(), ()), + ], None, ) .unwrap(); @@ -3808,7 +3868,10 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(fork_hash_root).unwrap() + ); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); @@ -3822,16 +3885,28 @@ pub(crate) mod tests { assert_eq!(None, bc.body(blocks[1]).unwrap()); assert_eq!(None, bc.body(blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); } else { for i in 0..5 { - assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]), + bc.body(blocks[i]).unwrap() + ); } } if matches!(pruning, BlocksPruning::KeepAll) { - assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(fork_hash_root).unwrap() + ); } else { assert_eq!(None, bc.body(fork_hash_root).unwrap()); } @@ -3852,8 +3927,16 @@ pub(crate) mod tests { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); let make_block = |index, parent, val: u64| { - insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) - .unwrap() + insert_block( + &backend, + index, + parent, + None, + H256::random(), + vec![UncheckedXt::new_transaction(val.into(), ())], + None, + ) + .unwrap() }; let block_0 = make_block(0, Default::default(), 0x00); @@ -3881,18 +3964,30 @@ pub(crate) mod tests { let bc = backend.blockchain(); assert_eq!(None, bc.body(block_1b).unwrap()); assert_eq!(None, bc.body(block_2b).unwrap()); - assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); - assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); - assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); - assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x00.into(), ())]), + bc.body(block_0).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x1a.into(), ())]), + bc.body(block_1a).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x2a.into(), ())]), + bc.body(block_2a).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x3a.into(), ())]), + bc.body(block_3a).unwrap() + ); } #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); - let x0 = ExtrinsicWrapper::from(0u64).encode(); - let x1 = ExtrinsicWrapper::from(1u64).encode(); + let x0 = UncheckedXt::new_transaction(0.into(), ()).encode(); + let x1 = UncheckedXt::new_transaction(1.into(), ()).encode(); let x0_hash = as sp_core::Hasher>::hash(&x0[1..]); let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); let index = vec![ @@ -3913,7 +4008,10 @@ pub(crate) mod tests { Default::default(), None, Default::default(), - vec![0u64.into(), 1u64.into()], + vec![ + UncheckedXt::new_transaction(0.into(), ()), + UncheckedXt::new_transaction(1.into(), ()), + ], Some(index), ) .unwrap(); @@ -3935,8 +4033,9 @@ pub(crate) mod tests { fn index_invalid_size() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); - let x0 = ExtrinsicWrapper::from(0u64).encode(); - let x1 = ExtrinsicWrapper::from(1u64).encode(); + let x0 = UncheckedXt::new_transaction(0.into(), ()).encode(); + let x1 = UncheckedXt::new_transaction(1.into(), ()).encode(); + let x0_hash = as sp_core::Hasher>::hash(&x0[..]); let x1_hash = as sp_core::Hasher>::hash(&x1[..]); let index = vec![ @@ -3957,7 +4056,10 @@ pub(crate) mod tests { Default::default(), None, Default::default(), - vec![0u64.into(), 1u64.into()], + vec![ + UncheckedXt::new_transaction(0.into(), ()), + UncheckedXt::new_transaction(1.into(), ()), + ], Some(index), ) .unwrap(); @@ -3971,7 +4073,7 @@ pub(crate) mod tests { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); - let x1 = ExtrinsicWrapper::from(0u64).encode(); + let x1 = UncheckedXt::new_transaction(0.into(), ()).encode(); let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); for i in 0..10 { let mut index = Vec::new(); @@ -3991,7 +4093,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], Some(index), ) .unwrap(); @@ -4025,7 +4127,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4040,7 +4142,7 @@ pub(crate) mod tests { blocks[1], None, sp_core::H256::random(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4054,7 +4156,7 @@ pub(crate) mod tests { blocks[0], None, sp_core::H256::random(), - vec![42.into()], + vec![UncheckedXt::new_transaction(42.into(), ())], None, ) .unwrap(); @@ -4528,7 +4630,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4543,7 +4645,10 @@ pub(crate) mod tests { // Check that we can properly access values when there is reference count // but no value. - assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(1.into(), ())]), + bc.body(blocks[1]).unwrap() + ); // Block 1 gets pinned three times backend.pin_block(blocks[1]).unwrap(); @@ -4560,27 +4665,42 @@ pub(crate) mod tests { // Block 0, 1, 2, 3 are pinned, so all values should be cached. // Block 4 is inside the pruning window, its value is in db. - assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0.into(), ())]), + bc.body(blocks[0]).unwrap() + ); - assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(1.into(), ())]), + bc.body(blocks[1]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(1))), bc.justifications(blocks[1]).unwrap() ); - assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(blocks[2]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(2))), bc.justifications(blocks[2]).unwrap() ); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(3))), bc.justifications(blocks[3]).unwrap() ); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() @@ -4611,7 +4731,10 @@ pub(crate) mod tests { assert!(bc.justifications(blocks[1]).unwrap().is_none()); // Block 4 is inside the pruning window and still kept - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() @@ -4619,9 +4742,16 @@ pub(crate) mod tests { // Block tree: // 0 -> 1 -> 2 -> 3 -> 4 -> 5 - let hash = - insert_block(&backend, 5, prev_hash, None, Default::default(), vec![5.into()], None) - .unwrap(); + let hash = insert_block( + &backend, + 5, + prev_hash, + None, + Default::default(), + vec![UncheckedXt::new_transaction(5.into(), ())], + None, + ) + .unwrap(); blocks.push(hash); backend.pin_block(blocks[4]).unwrap(); @@ -4636,12 +4766,18 @@ pub(crate) mod tests { assert!(bc.body(blocks[2]).unwrap().is_none()); assert!(bc.body(blocks[3]).unwrap().is_none()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() ); - assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(5.into(), ())]), + bc.body(blocks[5]).unwrap() + ); assert!(bc.header(blocks[5]).ok().flatten().is_some()); backend.unpin_block(blocks[4]); @@ -4651,9 +4787,16 @@ pub(crate) mod tests { // Append a justification to block 5. backend.append_justification(blocks[5], ([0, 0, 0, 1], vec![42])).unwrap(); - let hash = - insert_block(&backend, 6, blocks[5], None, Default::default(), vec![6.into()], None) - .unwrap(); + let hash = insert_block( + &backend, + 6, + blocks[5], + None, + Default::default(), + vec![UncheckedXt::new_transaction(6.into(), ())], + None, + ) + .unwrap(); blocks.push(hash); // Pin block 5 so it gets loaded into the cache on prune @@ -4666,7 +4809,10 @@ pub(crate) mod tests { op.mark_finalized(blocks[6], None).unwrap(); backend.commit_operation(op).unwrap(); - assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(5.into(), ())]), + bc.body(blocks[5]).unwrap() + ); assert!(bc.header(blocks[5]).ok().flatten().is_some()); let mut expected = Justifications::from(build_justification(5)); expected.append(([0, 0, 0, 1], vec![42])); @@ -4688,7 +4834,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4704,16 +4850,26 @@ pub(crate) mod tests { // Block tree: // 0 -> 1 -> 2 -> 3 -> 4 // \ -> 2 -> 3 - let fork_hash_root = - insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) - .unwrap(); + let fork_hash_root = insert_block( + &backend, + 2, + blocks[1], + None, + H256::random(), + vec![UncheckedXt::new_transaction(2.into(), ())], + None, + ) + .unwrap(); let fork_hash_3 = insert_block( &backend, 3, fork_hash_root, None, H256::random(), - vec![3.into(), 11.into()], + vec![ + UncheckedXt::new_transaction(3.into(), ()), + UncheckedXt::new_transaction(11.into(), ()), + ], None, ) .unwrap(); @@ -4734,14 +4890,35 @@ pub(crate) mod tests { } let bc = backend.blockchain(); - assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); - assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0.into(), ())]), + bc.body(blocks[0]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(1.into(), ())]), + bc.body(blocks[1]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(blocks[2]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); // Check the fork hashes. assert_eq!(None, bc.body(fork_hash_root).unwrap()); - assert_eq!(Some(vec![3.into(), 11.into()]), bc.body(fork_hash_3).unwrap()); + assert_eq!( + Some(vec![ + UncheckedXt::new_transaction(3.into(), ()), + UncheckedXt::new_transaction(11.into(), ()) + ]), + bc.body(fork_hash_3).unwrap() + ); // Unpin all blocks, except the forked one. for block in &blocks { diff --git a/substrate/client/db/src/utils.rs b/substrate/client/db/src/utils.rs index 0b591c967e60..a79f5ab3ac7d 100644 --- a/substrate/client/db/src/utils.rs +++ b/substrate/client/db/src/utils.rs @@ -613,14 +613,16 @@ impl<'a, 'b> codec::Input for JoinInput<'a, 'b> { mod tests { use super::*; use codec::Input; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; - type Block = RawBlock>; + use sp_runtime::testing::{Block as RawBlock, MockCallU64, TestXt}; + + pub type UncheckedXt = TestXt; + type Block = RawBlock; #[cfg(feature = "rocksdb")] #[test] fn database_type_subdir_migration() { use std::path::PathBuf; - type Block = RawBlock>; + type Block = RawBlock; fn check_dir_for_db_type( db_type: DatabaseType, 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/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index ac3f7a1b8c74..7649c8cc6370 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -549,7 +549,7 @@ mod tests { }; use sc_network_types::multiaddr::Multiaddr; use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, H256}, + testing::{Block as RawBlock, MockCallU64, TestXt, H256}, traits::NumberFor, }; use std::{ @@ -558,7 +558,7 @@ mod tests { sync::{Arc, Mutex}, }; - type Block = RawBlock>; + type Block = RawBlock>; macro_rules! push_msg { ($consensus:expr, $topic:expr, $hash: expr, $m:expr) => { diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index 8ae3de72f796..c8fd28e08109 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -70,7 +70,7 @@ 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 = { features = ["macros", "rt-multi-thread"], workspace = true, default-features = true } tokio-util = { features = ["compat"], workspace = true } tokio-test = { workspace = true } sc-block-builder = { workspace = true, default-features = true } @@ -83,5 +83,17 @@ sp-tracing = { workspace = true, default-features = true } substrate-test-runtime = { workspace = true } substrate-test-runtime-client = { 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..c1e18c7b7f47 --- /dev/null +++ b/substrate/client/network/benches/notifications_protocol.rs @@ -0,0 +1,348 @@ +// 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::NotificationEvent, + Litep2pNetworkBackend, NetworkBackend, NetworkWorker, NotificationMetrics, NotificationService, + Roles, +}; +use sc_network_common::{sync::message::BlockAnnouncesHandshake, ExHashT}; +use sc_network_types::build_multiaddr; +use sp_core::H256; +use sp_runtime::traits::{Block as BlockT, Zero}; +use std::{ + net::{IpAddr, Ipv4Addr, TcpListener}, + str::FromStr, +}; +use substrate_test_runtime_client::runtime; + +const MAX_SIZE: u64 = 2u64.pow(30); +const SAMPLE_SIZE: usize = 50; +const NOTIFICATIONS: usize = 50; +const EXPONENTS: &[(u32, &'static str)] = &[ + (6, "64B"), + (9, "512B"), + (12, "4KB"), + (15, "64KB"), + (18, "256KB"), + (21, "2MB"), + (24, "16MB"), + (27, "128MB"), +]; + +// TODO: It's be better to bind system-provided port when initializing the worker +fn get_listen_address() -> sc_network::Multiaddr { + let ip = Ipv4Addr::from_str("127.0.0.1").unwrap(); + let listener = TcpListener::bind((IpAddr::V4(ip), 0)).unwrap(); // Bind to a random port + let local_addr = listener.local_addr().unwrap(); + let port = local_addr.port(); + + build_multiaddr!(Ip4(ip), Tcp(port)) +} + +fn create_network_worker( + listen_addr: sc_network::Multiaddr, +) -> (N, Box) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let role = Role::Full; + let mut net_conf = NetworkConfiguration::new_local(); + net_conf.listen_addresses = vec![listen_addr]; + 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(); + + (worker, notification_service) +} + +async fn run_serially(size: usize, limit: usize) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let listen_address1 = get_listen_address(); + let listen_address2 = get_listen_address(); + let (worker1, mut notification_service1) = create_network_worker::(listen_address1); + let (worker2, mut notification_service2) = + create_network_worker::(listen_address2.clone()); + let peer_id2: sc_network::PeerId = worker2.network_service().local_peer_id().into(); + + worker1 + .network_service() + .add_reserved_peer(MultiaddrWithPeerId { multiaddr: listen_address2, peer_id: peer_id2 }) + .unwrap(); + + let network1_run = worker1.run(); + let network2_run = worker2.run(); + let (tx, rx) = async_channel::bounded(10); + + let network1 = tokio::spawn(async move { + let mut sent_counter = 0; + tokio::pin!(network1_run); + loop { + tokio::select! { + _ = &mut network1_run => {}, + event = notification_service1.next_event() => { + match event { + Some(NotificationEvent::NotificationStreamOpened { .. }) => { + sent_counter += 1; + notification_service1 + .send_async_notification(&peer_id2, vec![0; size]) + .await + .unwrap(); + }, + Some(NotificationEvent::NotificationStreamClosed { .. }) => { + if sent_counter >= limit { + break; + } + panic!("Unexpected stream closure {:?}", event); + } + event => panic!("Unexpected event {:?}", event), + }; + }, + message = rx.recv() => { + match message { + Ok(Some(_)) => { + sent_counter += 1; + notification_service1 + .send_async_notification(&peer_id2, vec![0; size]) + .await + .unwrap(); + }, + Ok(None) => break, + Err(err) => panic!("Unexpected error {:?}", err), + + } + } + } + } + }); + let network2 = tokio::spawn(async move { + let mut received_counter = 0; + tokio::pin!(network2_run); + loop { + tokio::select! { + _ = &mut network2_run => {}, + event = notification_service2.next_event() => { + match event { + Some(NotificationEvent::ValidateInboundSubstream { result_tx, .. }) => { + result_tx.send(sc_network::service::traits::ValidationResult::Accept).unwrap(); + }, + Some(NotificationEvent::NotificationStreamOpened { .. }) => {}, + Some(NotificationEvent::NotificationReceived { .. }) => { + received_counter += 1; + if received_counter >= limit { + let _ = tx.send(None).await; + break + } + let _ = tx.send(Some(())).await; + }, + event => panic!("Unexpected event {:?}", event), + }; + }, + } + } + }); + + let _ = tokio::join!(network1, network2); +} + +async fn run_with_backpressure(size: usize, limit: usize) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let listen_address1 = get_listen_address(); + let listen_address2 = get_listen_address(); + let (worker1, mut notification_service1) = create_network_worker::(listen_address1); + let (worker2, mut notification_service2) = + create_network_worker::(listen_address2.clone()); + let peer_id2: sc_network::PeerId = worker2.network_service().local_peer_id().into(); + + worker1 + .network_service() + .add_reserved_peer(MultiaddrWithPeerId { multiaddr: listen_address2, peer_id: peer_id2 }) + .unwrap(); + + let network1_run = worker1.run(); + let network2_run = worker2.run(); + + let network1 = tokio::spawn(async move { + let mut sent_counter = 0; + tokio::pin!(network1_run); + loop { + tokio::select! { + _ = &mut network1_run => {}, + event = notification_service1.next_event() => { + match event { + Some(NotificationEvent::NotificationStreamOpened { .. }) => { + while sent_counter < limit { + sent_counter += 1; + notification_service1 + .send_async_notification(&peer_id2, vec![0; size]) + .await + .unwrap(); + } + }, + Some(NotificationEvent::NotificationStreamClosed { .. }) => { + if sent_counter != limit { panic!("Stream closed unexpectedly") } + break + }, + event => panic!("Unexpected event {:?}", event), + }; + }, + } + } + }); + let network2 = tokio::spawn(async move { + let mut received_counter = 0; + tokio::pin!(network2_run); + loop { + tokio::select! { + _ = &mut network2_run => {}, + event = notification_service2.next_event() => { + match event { + Some(NotificationEvent::ValidateInboundSubstream { result_tx, .. }) => { + result_tx.send(sc_network::service::traits::ValidationResult::Accept).unwrap(); + }, + Some(NotificationEvent::NotificationStreamOpened { .. }) => {}, + Some(NotificationEvent::NotificationStreamClosed { .. }) => { + if received_counter != limit { panic!("Stream closed unexpectedly") } + break + }, + Some(NotificationEvent::NotificationReceived { .. }) => { + received_counter += 1; + if received_counter >= limit { break } + }, + event => panic!("Unexpected event {:?}", event), + }; + }, + } + } + }); + + let _ = tokio::join!(network1, network2); +} + +fn run_benchmark(c: &mut Criterion) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic); + let mut group = c.benchmark_group("notifications_benchmark"); + group.plot_config(plot_config); + + for &(exponent, label) in EXPONENTS.iter() { + let size = 2usize.pow(exponent); + group.throughput(Throughput::Bytes(NOTIFICATIONS as u64 * size as u64)); + + group.bench_with_input( + BenchmarkId::new("libp2p/serially", label), + &(size, NOTIFICATIONS), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| { + run_serially::>(size, limit) + }); + }, + ); + group.bench_with_input( + BenchmarkId::new("litep2p/serially", label), + &(size, NOTIFICATIONS), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| { + run_serially::( + size, limit, + ) + }); + }, + ); + group.bench_with_input( + BenchmarkId::new("libp2p/with_backpressure", label), + &(size, NOTIFICATIONS), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| { + run_with_backpressure::>( + size, limit, + ) + }); + }, + ); + group.bench_with_input( + BenchmarkId::new("litep2p/with_backpressure", label), + &(size, NOTIFICATIONS), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| { + run_with_backpressure::( + size, limit, + ) + }); + }, + ); + } +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(SAMPLE_SIZE); + targets = run_benchmark +} +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..b428d0d75ac5 --- /dev/null +++ b/substrate/client/network/benches/request_response_protocol.rs @@ -0,0 +1,303 @@ +// 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, + }, + IfDisconnected, Litep2pNetworkBackend, NetworkBackend, NetworkRequest, NetworkWorker, + NotificationMetrics, NotificationService, Roles, +}; +use sc_network_common::{sync::message::BlockAnnouncesHandshake, ExHashT}; +use sc_network_types::build_multiaddr; +use sp_core::H256; +use sp_runtime::traits::{Block as BlockT, Zero}; +use std::{ + net::{IpAddr, Ipv4Addr, TcpListener}, + str::FromStr, + time::Duration, +}; +use substrate_test_runtime_client::runtime; + +const MAX_SIZE: u64 = 2u64.pow(30); +const SAMPLE_SIZE: usize = 50; +const REQUESTS: usize = 50; +const EXPONENTS: &[(u32, &'static str)] = &[ + (6, "64B"), + (9, "512B"), + (12, "4KB"), + (15, "64KB"), + (18, "256KB"), + (21, "2MB"), + (24, "16MB"), + (27, "128MB"), +]; + +fn get_listen_address() -> sc_network::Multiaddr { + let ip = Ipv4Addr::from_str("127.0.0.1").unwrap(); + let listener = TcpListener::bind((IpAddr::V4(ip), 0)).unwrap(); // Bind to a random port + let local_addr = listener.local_addr().unwrap(); + let port = local_addr.port(); + + build_multiaddr!(Ip4(ip), Tcp(port)) +} + +pub fn create_network_worker( + listen_addr: sc_network::Multiaddr, +) -> (N, async_channel::Receiver, Box) +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 mut net_conf = NetworkConfiguration::new_local(); + net_conf.listen_addresses = vec![listen_addr]; + 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(); + + (worker, rx, notification_service) +} + +async fn run_serially(size: usize, limit: usize) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let listen_address1 = get_listen_address(); + let listen_address2 = get_listen_address(); + let (worker1, _rx1, _notification_service1) = create_network_worker::(listen_address1); + let service1 = worker1.network_service().clone(); + let (worker2, rx2, _notification_service2) = + create_network_worker::(listen_address2.clone()); + let peer_id2 = worker2.network_service().local_peer_id(); + + worker1.network_service().add_known_address(peer_id2, listen_address2.into()); + + let network1_run = worker1.run(); + let network2_run = worker2.run(); + let (break_tx, break_rx) = async_channel::bounded(10); + let requests = async move { + let mut sent_counter = 0; + while sent_counter < limit { + let _ = service1 + .request( + peer_id2.into(), + "/request-response/1".into(), + vec![0; 2], + None, + IfDisconnected::TryConnect, + ) + .await + .unwrap(); + sent_counter += 1; + } + let _ = break_tx.send(()).await; + }; + + let network1 = tokio::spawn(async move { + tokio::pin!(requests); + tokio::pin!(network1_run); + loop { + tokio::select! { + _ = &mut network1_run => {}, + _ = &mut requests => break, + } + } + }); + let network2 = tokio::spawn(async move { + tokio::pin!(network2_run); + loop { + tokio::select! { + _ = &mut network2_run => {}, + 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(size: usize, limit: usize) +where + B: BlockT + 'static, + H: ExHashT, + N: NetworkBackend, +{ + let listen_address1 = get_listen_address(); + let listen_address2 = get_listen_address(); + let (worker1, _rx1, _notification_service1) = create_network_worker::(listen_address1); + let service1 = worker1.network_service().clone(); + let (worker2, rx2, _notification_service2) = + create_network_worker::(listen_address2.clone()); + let peer_id2 = worker2.network_service().local_peer_id(); + + worker1.network_service().add_known_address(peer_id2, listen_address2.into()); + + let network1_run = worker1.run(); + let network2_run = worker2.run(); + let (break_tx, break_rx) = async_channel::bounded(10); + let requests = futures::future::join_all((0..limit).into_iter().map(|_| { + let (tx, rx) = futures::channel::oneshot::channel(); + service1.start_request( + peer_id2.into(), + "/request-response/1".into(), + vec![0; 8], + None, + tx, + IfDisconnected::TryConnect, + ); + rx + })); + + let network1 = tokio::spawn(async move { + tokio::pin!(requests); + tokio::pin!(network1_run); + loop { + tokio::select! { + _ = &mut network1_run => {}, + responses = &mut requests => { + for res in responses { + res.unwrap().unwrap(); + } + let _ = break_tx.send(()).await; + break; + }, + } + } + }); + let network2 = tokio::spawn(async move { + tokio::pin!(network2_run); + loop { + tokio::select! { + _ = &mut network2_run => {}, + 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); +} + +fn run_benchmark(c: &mut Criterion) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic); + let mut group = c.benchmark_group("request_response_benchmark"); + group.plot_config(plot_config); + + for &(exponent, label) in EXPONENTS.iter() { + let size = 2usize.pow(exponent); + group.throughput(Throughput::Bytes(REQUESTS as u64 * size as u64)); + group.bench_with_input( + BenchmarkId::new("libp2p/serially", label), + &(size, REQUESTS), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| { + run_serially::>(size, limit) + }); + }, + ); + group.bench_with_input( + BenchmarkId::new("litep2p/serially", label), + &(size, REQUESTS), + |b, &(size, limit)| { + b.to_async(&rt).iter(|| { + run_serially::( + size, limit, + ) + }); + }, + ); + } +} + +criterion_group! { + name = benches; + config = Criterion::default().sample_size(SAMPLE_SIZE); + targets = run_benchmark +} +criterion_main!(benches); diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 5ecbec52d507..dbb72381b660 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -375,18 +375,18 @@ 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::RandomKademliaStarted => BehaviourOut::RandomKademliaStarted, } } diff --git a/substrate/client/network/src/discovery.rs b/substrate/client/network/src/discovery.rs index 86c66c22701c..8080bda9a574 100644 --- a/substrate/client/network/src/discovery.rs +++ b/substrate/client/network/src/discovery.rs @@ -648,7 +648,7 @@ impl NetworkBehaviour for DiscoveryBehaviour { let mut list: LinkedHashSet<_> = self .permanent_addresses .iter() - .filter_map(|(p, a)| (*p == peer_id).then_some(a.clone())) + .filter_map(|(p, a)| (*p == peer_id).then(|| a.clone())) .collect(); if let Some(ephemeral_addresses) = self.ephemeral_addresses.get(&peer_id) { @@ -749,16 +749,28 @@ 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}", ); } } diff --git a/substrate/client/network/src/event.rs b/substrate/client/network/src/event.rs index 5400d11cb6ac..626cf516a7ec 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)] diff --git a/substrate/client/network/src/litep2p/discovery.rs b/substrate/client/network/src/litep2p/discovery.rs index 5fe944cadc0b..3a9454e317cc 100644 --- a/substrate/client/network/src/litep2p/discovery.rs +++ b/substrate/client/network/src/litep2p/discovery.rs @@ -27,7 +27,6 @@ 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::{ @@ -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::{ @@ -116,7 +116,16 @@ pub enum DiscoveryEvent { /// New external address discovered. ExternalAddressDiscovered { - /// Discovered addresses. + /// Discovered address. + address: Multiaddr, + }, + + /// The external address has expired. + /// + /// This happens when the internal buffers exceed the maximum number of external addresses, + /// and this address is the oldest one. + ExternalAddressExpired { + /// Expired address. address: Multiaddr, }, @@ -153,6 +162,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>, @@ -224,6 +236,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>, @@ -264,6 +277,7 @@ impl Discovery { ( Self { + local_peer_id, ping_event_stream, identify_event_stream, mdns_event_stream, @@ -423,7 +437,13 @@ impl Discovery { } /// Check if `address` can be considered a new external address. - fn is_new_external_address(&mut self, address: &Multiaddr, peer: PeerId) -> bool { + /// + /// If this address replaces an older address, the expired address is returned. + fn is_new_external_address( + &mut self, + address: &Multiaddr, + peer: PeerId, + ) -> (bool, Option) { log::trace!(target: LOG_TARGET, "verify new external address: {address}"); // is the address one of our known addresses @@ -434,7 +454,7 @@ impl Discovery { .chain(self.public_addresses.iter()) .any(|known_address| Discovery::is_known_address(&known_address, &address)) { - return true + return (true, None) } match self.address_confirmations.get(address) { @@ -442,15 +462,31 @@ impl Discovery { confirmations.insert(peer); if confirmations.len() >= MIN_ADDRESS_CONFIRMATIONS { - return true + return (true, None) } }, None => { + let oldest = (self.address_confirmations.len() >= + self.address_confirmations.limiter().max_length() as usize) + .then(|| { + self.address_confirmations.pop_oldest().map(|(address, peers)| { + if peers.len() >= MIN_ADDRESS_CONFIRMATIONS { + return Some(address) + } else { + None + } + }) + }) + .flatten() + .flatten(); + self.address_confirmations.insert(address.clone(), Default::default()); + + return (false, oldest) }, } - false + (false, None) } } @@ -522,7 +558,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) { @@ -545,6 +581,9 @@ impl Stream for Discovery { return Poll::Ready(Some(DiscoveryEvent::IncomingRecord { record })) }, + // Content provider events are ignored for now. + Poll::Ready(Some(KademliaEvent::GetProvidersSuccess { .. })) | + Poll::Ready(Some(KademliaEvent::IncomingProvider { .. })) => {}, } match Pin::new(&mut this.identify_event_stream).poll_next(cx) { @@ -557,10 +596,43 @@ impl Stream for Discovery { observed_address, .. })) => { - if this.is_new_external_address(&observed_address, peer) { - this.pending_events.push_back(DiscoveryEvent::ExternalAddressDiscovered { - address: observed_address.clone(), - }); + 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(), + }); + } } 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 277f0759729c..10cf9f4da36d 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}; @@ -540,6 +540,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(), @@ -710,8 +711,8 @@ impl NetworkBackend for Litep2pNetworkBac self.pending_put_values.insert(query_id, (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; + let kademlia_key = record.key.clone(); + let query_id = self.discovery.put_value_to_peers(record.into(), peers, update_local_storage).await; self.pending_put_values.insert(query_id, (kademlia_key, Instant::now())); } @@ -835,7 +836,7 @@ impl NetworkBackend for Litep2pNetworkBac self.event_streams.send( Event::Dht( DhtEvent::ValueFound( - record + record.into() ) ) ); @@ -863,7 +864,7 @@ impl NetworkBackend for Litep2pNetworkBac ); self.event_streams.send(Event::Dht( - DhtEvent::ValuePut(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValuePut(key) )); if let Some(ref metrics) = self.metrics { @@ -889,7 +890,7 @@ impl NetworkBackend for Litep2pNetworkBac ); self.event_streams.send(Event::Dht( - DhtEvent::ValuePutFailed(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValuePutFailed(key) )); if let Some(ref metrics) = self.metrics { @@ -907,7 +908,7 @@ impl NetworkBackend for Litep2pNetworkBac ); self.event_streams.send(Event::Dht( - DhtEvent::ValueNotFound(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValueNotFound(key) )); if let Some(ref metrics) = self.metrics { @@ -935,6 +936,25 @@ impl NetworkBackend for Litep2pNetworkBac }, } } + Some(DiscoveryEvent::ExternalAddressExpired{ address }) => { + let local_peer_id = self.litep2p.local_peer_id(); + + // Litep2p requires the peer ID to be present in the address. + let address = if !std::matches!(address.iter().last(), Some(Protocol::P2p(_))) { + address.with(Protocol::P2p(*local_peer_id.as_ref())) + } else { + address + }; + + if self.litep2p.public_addresses().remove_address(&address) { + log::info!(target: LOG_TARGET, "🔍 Expired external address for our node: {address}"); + } else { + log::warn!( + target: LOG_TARGET, + "🔍 Failed to remove expired external address {address:?}" + ); + } + } Some(DiscoveryEvent::Ping { peer, rtt }) => { log::trace!( target: LOG_TARGET, @@ -944,7 +964,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, @@ -1054,7 +1074,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..fa1d47e5a1b7 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}, @@ -266,12 +266,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(), 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/service.rs b/substrate/client/network/src/service.rs index 71d0b45aa06d..5e5e4ee28589 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -68,7 +68,6 @@ use libp2p::{ 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 +79,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::{ @@ -1455,17 +1455,17 @@ 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::AddKnownAddress(peer_id, addr) => self.network_service.behaviour_mut().add_known_address(peer_id, addr), ServiceToWorkerMsg::EventStream(sender) => self.event_streams.push(sender), diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index bd4f83c7fd44..f5dd2995acb1 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: 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/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/blocks.rs b/substrate/client/network/sync/src/blocks.rs index af88c5245dcb..eedba18bebe3 100644 --- a/substrate/client/network/sync/src/blocks.rs +++ b/substrate/client/network/sync/src/blocks.rs @@ -265,9 +265,9 @@ mod test { use sc_network_common::sync::message; use sc_network_types::PeerId; use sp_core::H256; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; + use sp_runtime::testing::{Block as RawBlock, MockCallU64, TestXt}; - type Block = RawBlock>; + type Block = RawBlock>; fn is_empty(bc: &BlockCollection) -> bool { bc.blocks.is_empty() && bc.peer_requests.is_empty() diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index dceea9954c6e..cc2089d1974c 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,8 +94,6 @@ 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. @@ -264,10 +254,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 +278,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 +403,6 @@ where None }, pending_responses: PendingResponses::new(), - block_downloader, import_queue, }, SyncingService::new(tx, num_connected, is_major_syncing), @@ -583,57 +568,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)) => { @@ -1000,160 +970,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() - })?; - - 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; + fn process_response_event(&mut self, response_event: ResponseEvent) { + let ResponseEvent { peer_id, key, response: response_result } = 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:?}."); @@ -1214,7 +1036,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 +1047,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 b0e28d00f64a..18170b77881e 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync.rs @@ -29,25 +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 codec::Encode; +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, }; @@ -57,13 +60,13 @@ use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ traits::{ - Block as BlockT, CheckedSub, Hash, HashingFor, Header as HeaderT, NumberFor, One, - SaturatedConversion, Zero, + Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero, }, EncodedJustification, Justifications, }; use std::{ + any::Any, collections::{HashMap, HashSet}, ops::Range, sync::Arc, @@ -125,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 { @@ -326,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. @@ -350,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)), } @@ -566,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( @@ -865,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); @@ -908,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, @@ -915,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 { @@ -937,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) { @@ -1077,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( @@ -1250,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 @@ -1336,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( @@ -1550,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(_) => { @@ -1833,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; } @@ -1857,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)); } } } @@ -1865,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 { @@ -1893,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)); @@ -2305,24 +2402,6 @@ pub fn validate_blocks( return Err(BadPeer(*peer_id, rep::BAD_BLOCK)); } } - if let (Some(header), Some(body)) = (&b.header, &b.body) { - let expected = *header.extrinsics_root(); - let got = HashingFor::::ordered_trie_root( - body.iter().map(Encode::encode).collect(), - sp_runtime::StateVersion::V0, - ); - if expected != got { - debug!( - target: LOG_TARGET, - "Bad extrinsic root for a block {} received from {}. Expected {:?}, got {:?}", - b.hash, - peer_id, - expected, - got, - ); - return Err(BadPeer(*peer_id, rep::BAD_BLOCK)); - } - } } Ok(blocks.first().and_then(|b| b.header.as_ref()).map(|h| *h.number())) 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 a04ab8be4fea..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)); } } } @@ -173,7 +169,7 @@ impl StateStrategy { peer_id: PeerId, announce: &BlockAnnounce, ) -> Option<(B::Hash, NumberFor)> { - is_best.then_some({ + is_best.then(|| { let best_number = *announce.header.number(); let best_hash = announce.header.hash(); if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { @@ -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 cce6a93caf43..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)); } } } @@ -301,7 +301,7 @@ where peer_id: PeerId, announce: &BlockAnnounce, ) -> Option<(B::Hash, NumberFor)> { - is_best.then_some({ + is_best.then(|| { let best_number = *announce.header.number(); let best_hash = announce.header.hash(); if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { @@ -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..5745a34378df 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 { diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index 06e243342fb2..825481314c67 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, }; @@ -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/src/lib.rs b/substrate/client/network/transactions/src/lib.rs index a241041968fd..44fa702ef6d4 100644 --- a/substrate/client/network/transactions/src/lib.rs +++ b/substrate/client/network/transactions/src/lib.rs @@ -462,6 +462,8 @@ where if let Some(transaction) = self.transaction_pool.transaction(hash) { let propagated_to = self.do_propagate_transactions(&[(hash.clone(), transaction)]); self.transaction_pool.on_broadcasted(propagated_to); + } else { + debug!(target: "sync", "Propagating transaction failure [{:?}]", hash); } } @@ -478,7 +480,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..7438eaeffcd2 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.44.6", 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 bbbe7018d106..71b40211e126 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -22,15 +22,15 @@ codec = { features = ["derive"], workspace = true, default-features = true } fnv = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } -hyperv14 = { features = [ - "http2", - "stream", -], workspace = true, default-features = true } -hyper-rustls = { features = ["http2"], workspace = true } +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 } 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 } diff --git a/substrate/client/offchain/src/api.rs b/substrate/client/offchain/src/api.rs index 19ccdbcf498f..a5981f14c093 100644 --- a/substrate/client/offchain/src/api.rs +++ b/substrate/client/offchain/src/api.rs @@ -326,7 +326,7 @@ mod tests { fn offchain_api() -> (Api, AsyncApi) { sp_tracing::try_init_simple(); let mock = Arc::new(TestNetwork()); - let shared_client = SharedClient::new(); + let shared_client = SharedClient::new().unwrap(); AsyncApi::new(mock, false, shared_client) } diff --git a/substrate/client/offchain/src/api/http.rs b/substrate/client/offchain/src/api/http.rs index 73407b1359d7..56f5c0230094 100644 --- a/substrate/client/offchain/src/api/http.rs +++ b/substrate/client/offchain/src/api/http.rs @@ -27,14 +27,14 @@ //! (i.e.: the socket should continue being processed) in the background even if the runtime isn't //! actively calling any function. -use hyperv14 as hyper; - use crate::api::timestamp; use bytes::buf::{Buf, Reader}; use fnv::FnvHashMap; use futures::{channel::mpsc, future, prelude::*}; -use hyper::{client, Body, Client as HyperClient}; +use http_body_util::{combinators::BoxBody, StreamBody}; +use hyper::body::Body as _; use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; +use hyper_util::{client::legacy as client, rt::TokioExecutor}; use once_cell::sync::Lazy; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_core::offchain::{HttpError, HttpRequestId, HttpRequestStatus, Timestamp}; @@ -48,21 +48,26 @@ use std::{ const LOG_TARGET: &str = "offchain-worker::http"; +pub type Body = BoxBody; + +type Sender = mpsc::Sender, hyper::Error>>; +type Receiver = mpsc::Receiver, hyper::Error>>; + +type HyperClient = client::Client, Body>; +type LazyClient = Lazy HyperClient + Send>>; + /// Wrapper struct used for keeping the hyper_rustls client running. #[derive(Clone)] -pub struct SharedClient(Arc, Body>>>); +pub struct SharedClient(Arc); impl SharedClient { - pub fn new() -> Self { - Self(Arc::new(Lazy::new(|| { - let connector = HttpsConnectorBuilder::new() - .with_native_roots() - .https_or_http() - .enable_http1() - .enable_http2() - .build(); - HyperClient::builder().build(connector) - }))) + pub fn new() -> std::io::Result { + let builder = HttpsConnectorBuilder::new() + .with_provider_and_native_roots(rustls::crypto::ring::default_provider())?; + Ok(Self(Arc::new(Lazy::new(Box::new(|| { + let connector = builder.https_or_http().enable_http1().enable_http2().build(); + client::Client::builder(TokioExecutor::new()).build(connector) + }))))) } } @@ -105,23 +110,23 @@ pub struct HttpApi { /// One active request within `HttpApi`. enum HttpApiRequest { /// The request object is being constructed locally and not started yet. - NotDispatched(hyper::Request, hyper::body::Sender), + NotDispatched(hyper::Request, Sender), /// The request has been dispatched and we're in the process of sending out the body (if the /// field is `Some`) or waiting for a response (if the field is `None`). - Dispatched(Option), + Dispatched(Option), /// Received a response. Response(HttpApiRequestRp), /// A request has been dispatched but the worker notified us of an error. We report this /// failure to the user as an `IoError` and remove the request from the list as soon as /// possible. - Fail(hyper::Error), + Fail(client::Error), } /// A request within `HttpApi` that has received a response. struct HttpApiRequestRp { /// We might still be writing the request's body when the response comes. /// This field allows to continue writing that body. - sending_body: Option, + sending_body: Option, /// Status code of the response. status_code: hyper::StatusCode, /// Headers of the response. @@ -132,7 +137,7 @@ struct HttpApiRequestRp { /// Elements extracted from the channel are first put into `current_read_chunk`. /// If the channel produces an error, then that is translated into an `IoError` and the request /// is removed from the list. - body: stream::Fuse>>, + body: stream::Fuse, /// Chunk that has been extracted from the channel and that is currently being read. /// Reading data from the response should read from this field in priority. current_read_chunk: Option>, @@ -144,7 +149,9 @@ impl HttpApi { // Start by building the prototype of the request. // We do this first so that we don't touch anything in `self` if building the prototype // fails. - let (body_sender, body) = hyper::Body::channel(); + let (body_sender, receiver) = mpsc::channel(0); + let body = StreamBody::new(receiver); + let body = BoxBody::new(body); let mut request = hyper::Request::new(body); *request.method_mut() = hyper::Method::from_bytes(method.as_bytes()).map_err(|_| ())?; *request.uri_mut() = hyper::Uri::from_maybe_shared(uri.to_owned()).map_err(|_| ())?; @@ -158,7 +165,7 @@ impl HttpApi { target: LOG_TARGET, "Overflow in offchain worker HTTP request ID assignment" ); - return Err(()) + return Err(()); }, }; self.requests @@ -213,7 +220,7 @@ impl HttpApi { // Closure that writes data to a sender, taking the deadline into account. Can return `Ok` // (if the body has been written), or `DeadlineReached`, or `IoError`. // If `IoError` is returned, don't forget to remove the request from the list. - let mut poll_sender = move |sender: &mut hyper::body::Sender| -> Result<(), HttpError> { + let mut poll_sender = move |sender: &mut Sender| -> Result<(), HttpError> { let mut when_ready = future::maybe_done(future::poll_fn(|cx| sender.poll_ready(cx))); futures::executor::block_on(future::select(&mut when_ready, &mut deadline)); match when_ready { @@ -221,12 +228,15 @@ impl HttpApi { future::MaybeDone::Done(Err(_)) => return Err(HttpError::IoError), future::MaybeDone::Future(_) | future::MaybeDone::Gone => { debug_assert!(matches!(deadline, future::MaybeDone::Done(..))); - return Err(HttpError::DeadlineReached) + return Err(HttpError::DeadlineReached); }, }; futures::executor::block_on( - sender.send_data(hyper::body::Bytes::from(chunk.to_owned())), + async { + future::poll_fn(|cx| sender.poll_ready(cx)).await?; + sender.start_send(Ok(hyper::body::Frame::data(hyper::body::Bytes::from(chunk.to_owned())))) + } ) .map_err(|_| { tracing::error!(target: "offchain-worker::http", "HTTP sender refused data despite being ready"); @@ -250,13 +260,13 @@ impl HttpApi { match poll_sender(&mut sender) { Err(HttpError::IoError) => { tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Encountered io error while trying to add new chunk to body"); - return Err(HttpError::IoError) + return Err(HttpError::IoError); }, other => { tracing::debug!(target: LOG_TARGET, id = %request_id.0, res = ?other, "Added chunk to body"); self.requests .insert(request_id, HttpApiRequest::Dispatched(Some(sender))); - return other + return other; }, } } else { @@ -265,7 +275,7 @@ impl HttpApi { // Writing an empty body is a hint that we should stop writing. Dropping // the sender. self.requests.insert(request_id, HttpApiRequest::Dispatched(None)); - return Ok(()) + return Ok(()); } }, @@ -281,13 +291,13 @@ impl HttpApi { ) { Err(HttpError::IoError) => { tracing::debug!(target: LOG_TARGET, id = %request_id.0, "Encountered io error while trying to add new chunk to body"); - return Err(HttpError::IoError) + return Err(HttpError::IoError); }, other => { tracing::debug!(target: LOG_TARGET, id = %request_id.0, res = ?other, "Added chunk to body"); self.requests .insert(request_id, HttpApiRequest::Response(response)); - return other + return other; }, } } else { @@ -302,7 +312,7 @@ impl HttpApi { ..response }), ); - return Ok(()) + return Ok(()); } }, @@ -311,7 +321,7 @@ impl HttpApi { // If the request has already failed, return without putting back the request // in the list. - return Err(HttpError::IoError) + return Err(HttpError::IoError); }, v @ HttpApiRequest::Dispatched(None) | @@ -320,7 +330,7 @@ impl HttpApi { // We have already finished sending this body. self.requests.insert(request_id, v); - return Err(HttpError::Invalid) + return Err(HttpError::Invalid); }, } } @@ -340,7 +350,7 @@ impl HttpApi { Some(HttpApiRequest::Dispatched(sending_body)) | Some(HttpApiRequest::Response(HttpApiRequestRp { sending_body, .. })) => { let _ = sending_body.take(); - continue + continue; }, _ => continue, }; @@ -405,7 +415,7 @@ impl HttpApi { }, } } - return output + return output; } } @@ -418,7 +428,7 @@ impl HttpApi { msg } else { debug_assert!(matches!(deadline, future::MaybeDone::Done(..))); - continue + continue; } }; @@ -458,7 +468,7 @@ impl HttpApi { None => { tracing::error!(target: "offchain-worker::http", "Worker has crashed"); - return ids.iter().map(|_| HttpRequestStatus::IoError).collect() + return ids.iter().map(|_| HttpRequestStatus::IoError).collect(); }, } } @@ -498,14 +508,14 @@ impl HttpApi { // and we still haven't received a response. Some(rq @ HttpApiRequest::Dispatched(_)) => { self.requests.insert(request_id, rq); - return Err(HttpError::DeadlineReached) + return Err(HttpError::DeadlineReached); }, // The request has failed. Some(HttpApiRequest::Fail { .. }) => return Err(HttpError::IoError), // Request hasn't been dispatched yet; reading the body is invalid. Some(rq @ HttpApiRequest::NotDispatched(_, _)) => { self.requests.insert(request_id, rq); - return Err(HttpError::Invalid) + return Err(HttpError::Invalid); }, None => return Err(HttpError::Invalid), }; @@ -526,12 +536,12 @@ impl HttpApi { ..response }), ); - return Ok(n) + return Ok(n); }, Err(err) => { // This code should never be reached unless there's a logic error somewhere. tracing::error!(target: "offchain-worker::http", "Failed to read from current read chunk: {:?}", err); - return Err(HttpError::IoError) + return Err(HttpError::IoError); }, } } @@ -544,7 +554,10 @@ impl HttpApi { if let future::MaybeDone::Done(next_body) = next_body { match next_body { - Some(Ok(chunk)) => response.current_read_chunk = Some(chunk.reader()), + Some(Ok(chunk)) => + if let Ok(chunk) = chunk.into_data() { + response.current_read_chunk = Some(chunk.reader()); + }, Some(Err(_)) => return Err(HttpError::IoError), None => return Ok(0), // eof } @@ -552,7 +565,7 @@ impl HttpApi { if let future::MaybeDone::Done(_) = deadline { self.requests.insert(request_id, HttpApiRequest::Response(response)); - return Err(HttpError::DeadlineReached) + return Err(HttpError::DeadlineReached); } } } @@ -587,7 +600,7 @@ enum ApiToWorker { /// ID to send back when the response comes back. id: HttpRequestId, /// Request to start executing. - request: hyper::Request, + request: hyper::Request, }, } @@ -608,14 +621,14 @@ enum WorkerToApi { /// the next item. /// Can also be used to send an error, in case an error happened on the HTTP socket. After /// an error is sent, the channel will close. - body: mpsc::Receiver>, + body: Receiver, }, /// A request has failed because of an error. The request is then no longer valid. Fail { /// The ID that was passed to the worker. id: HttpRequestId, /// Error that happened. - error: hyper::Error, + error: client::Error, }, } @@ -626,7 +639,7 @@ pub struct HttpWorker { /// Used to receive messages from the `HttpApi`. from_api: TracingUnboundedReceiver, /// The engine that runs HTTP requests. - http_client: Arc, Body>>>, + http_client: Arc, /// HTTP requests that are being worked on by the engine. requests: Vec<(HttpRequestId, HttpWorkerRequest)>, } @@ -634,13 +647,13 @@ pub struct HttpWorker { /// HTTP request being processed by the worker. enum HttpWorkerRequest { /// Request has been dispatched and is waiting for a response from the Internet. - Dispatched(hyper::client::ResponseFuture), + Dispatched(client::ResponseFuture), /// Progressively reading the body of the response and sending it to the channel. ReadBody { /// Body to read `Chunk`s from. Only used if the channel is ready to accept data. - body: hyper::Body, + body: Body, /// Channel to the [`HttpApi`] where we send the chunks to. - tx: mpsc::Sender>, + tx: Sender, }, } @@ -663,12 +676,12 @@ impl Future for HttpWorker { let response = match Future::poll(Pin::new(&mut future), cx) { Poll::Pending => { me.requests.push((id, HttpWorkerRequest::Dispatched(future))); - continue + continue; }, Poll::Ready(Ok(response)) => response, Poll::Ready(Err(error)) => { let _ = me.to_api.unbounded_send(WorkerToApi::Fail { id, error }); - continue // don't insert the request back + continue; // don't insert the request back }, }; @@ -684,9 +697,12 @@ impl Future for HttpWorker { body: body_rx, }); - me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx: body_tx })); + me.requests.push(( + id, + HttpWorkerRequest::ReadBody { body: Body::new(body), tx: body_tx }, + )); cx.waker().wake_by_ref(); // reschedule in order to poll the new future - continue + continue; }, HttpWorkerRequest::ReadBody { mut body, mut tx } => { @@ -697,12 +713,11 @@ impl Future for HttpWorker { Poll::Ready(Err(_)) => continue, // don't insert the request back Poll::Pending => { me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx })); - continue + continue; }, } - // `tx` is ready. Read a chunk from the socket and send it to the channel. - match Stream::poll_next(Pin::new(&mut body), cx) { + match Pin::new(&mut body).poll_frame(cx) { Poll::Ready(Some(Ok(chunk))) => { let _ = tx.start_send(Ok(chunk)); me.requests.push((id, HttpWorkerRequest::ReadBody { body, tx })); @@ -762,19 +777,22 @@ mod tests { }; use crate::api::timestamp; use core::convert::Infallible; - use futures::{future, StreamExt}; + use futures::future; + use http_body_util::BodyExt; use sp_core::offchain::{Duration, Externalities, HttpError, HttpRequestId, HttpRequestStatus}; use std::sync::LazyLock; // Using LazyLock to avoid spawning lots of different SharedClients, // as spawning a SharedClient is CPU-intensive and opens lots of fds. - static SHARED_CLIENT: LazyLock = LazyLock::new(|| SharedClient::new()); + static SHARED_CLIENT: LazyLock = LazyLock::new(|| SharedClient::new().unwrap()); // Returns an `HttpApi` whose worker is ran in the background, and a `SocketAddr` to an HTTP // server that runs in the background as well. macro_rules! build_api_server { () => { - build_api_server!(hyper::Response::new(hyper::Body::from("Hello World!"))) + build_api_server!(hyper::Response::new(http_body_util::Full::new( + hyper::body::Bytes::from("Hello World!") + ))) }; ( $response:expr ) => {{ let hyper_client = SHARED_CLIENT.clone(); @@ -785,21 +803,32 @@ mod tests { let rt = tokio::runtime::Runtime::new().unwrap(); let worker = rt.spawn(worker); let server = rt.spawn(async move { - let server = hyper::Server::bind(&"127.0.0.1:0".parse().unwrap()).serve( - hyper::service::make_service_fn(|_| async move { - Ok::<_, Infallible>(hyper::service::service_fn( - move |req: hyper::Request| async move { - // Wait until the complete request was received and processed, - // otherwise the tests are flaky. - let _ = req.into_body().collect::>().await; - - Ok::<_, Infallible>($response) - }, - )) - }), - ); - let _ = addr_tx.send(server.local_addr()); - server.await.map_err(drop) + let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 0)); + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); + let _ = addr_tx.send(listener.local_addr().unwrap()); + loop { + let (stream, _) = listener.accept().await.unwrap(); + let io = hyper_util::rt::TokioIo::new(stream); + tokio::task::spawn(async move { + if let Err(err) = hyper::server::conn::http1::Builder::new() + .serve_connection( + io, + hyper::service::service_fn( + move |req: hyper::Request| async move { + // Wait until the complete request was received and + // processed, otherwise the tests are flaky. + let _ = req.into_body().collect().await; + + Ok::<_, Infallible>($response) + }, + ), + ) + .await + { + eprintln!("Error serving connection: {:?}", err); + } + }); + } }); let _ = rt.block_on(future::join(worker, server)); }); @@ -839,7 +868,7 @@ mod tests { let (mut api, addr) = build_api_server!(hyper::Response::builder() .version(hyper::Version::HTTP_2) - .body(hyper::Body::from("Hello World!")) + .body(http_body_util::Full::new(hyper::body::Bytes::from("Hello World!"))) .unwrap()); let id = api.request_start("POST", &format!("http://{}", addr)).unwrap(); @@ -1097,7 +1126,7 @@ mod tests { #[test] fn shared_http_client_is_only_initialized_on_access() { - let shared_client = SharedClient::new(); + let shared_client = SharedClient::new().unwrap(); { let mock = Arc::new(TestNetwork()); @@ -1112,7 +1141,7 @@ mod tests { // Check that the http client wasn't initialized, because it wasn't used. assert!(Lazy::into_value(Arc::try_unwrap(shared_client.0).unwrap()).is_err()); - let shared_client = SharedClient::new(); + let shared_client = SharedClient::new().unwrap(); { let mock = Arc::new(TestNetwork()); diff --git a/substrate/client/offchain/src/lib.rs b/substrate/client/offchain/src/lib.rs index 7cee64e6ce7e..b0a7a66520b7 100644 --- a/substrate/client/offchain/src/lib.rs +++ b/substrate/client/offchain/src/lib.rs @@ -153,14 +153,14 @@ impl OffchainWorkers { enable_http_requests, custom_extensions, }: OffchainWorkerOptions, - ) -> Self { - Self { + ) -> std::io::Result { + Ok(Self { runtime_api_provider, thread_pool: Mutex::new(ThreadPool::with_name( "offchain-worker".into(), num_cpus::get(), )), - shared_http_client: api::SharedClient::new(), + shared_http_client: api::SharedClient::new()?, enable_http_requests, keystore, offchain_db: offchain_db.map(OffchainDb::new), @@ -168,7 +168,7 @@ impl OffchainWorkers { is_validator, network_provider, custom_extensions: Box::new(custom_extensions), - } + }) } } @@ -446,8 +446,13 @@ mod tests { let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); let network = Arc::new(TestNetwork()); let header = client.header(client.chain_info().genesis_hash).unwrap().unwrap(); @@ -461,7 +466,8 @@ mod tests { is_validator: false, enable_http_requests: false, custom_extensions: |_| Vec::new(), - }); + }) + .unwrap(); futures::executor::block_on(offchain.on_block_imported(&header)); // then diff --git a/substrate/client/rpc-servers/src/utils.rs b/substrate/client/rpc-servers/src/utils.rs index d9b2db7af133..51cce6224298 100644 --- a/substrate/client/rpc-servers/src/utils.rs +++ b/substrate/client/rpc-servers/src/utils.rs @@ -193,14 +193,11 @@ pub(crate) fn host_filtering(enabled: bool, addr: SocketAddr) -> Option, Block: BlockT, Client> { max_lagging_distance: usize, /// Phantom member to pin the block type. _phantom: PhantomData, + /// The maximum number of pending messages per subscription. + subscription_buffer_cap: usize, } impl, Block: BlockT, Client> ChainHead { @@ -148,6 +153,7 @@ impl, Block: BlockT, Client> ChainHead { backend, ), max_lagging_distance: config.max_lagging_distance, + subscription_buffer_cap: config.subscription_buffer_cap, _phantom: PhantomData, } } @@ -196,6 +202,7 @@ where let backend = self.backend.clone(); let client = self.client.clone(); let max_lagging_distance = self.max_lagging_distance; + let subscription_buffer_cap = self.subscription_buffer_cap; let fut = async move { // Ensure the current connection ID has enough space to accept a new subscription. @@ -231,6 +238,7 @@ where with_runtime, sub_id.clone(), max_lagging_distance, + subscription_buffer_cap, ); let result = chain_head_follow.generate_events(sink, sub_data).await; if let Err(SubscriptionManagementError::BlockDistanceTooLarge) = result { diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index ebb72ed3d156..e9975b36b4a1 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -24,13 +24,12 @@ use crate::chain_head::{ BestBlockChanged, Finalized, FollowEvent, Initialized, NewBlock, RuntimeEvent, RuntimeVersionEvent, }, - subscription::{SubscriptionManagement, SubscriptionManagementError}, + subscription::{InsertedSubscriptionData, SubscriptionManagement, SubscriptionManagementError}, }; use futures::{ channel::oneshot, - stream::{self, Stream, StreamExt}, + stream::{self, Stream, StreamExt, TryStreamExt}, }; -use futures_util::future::Either; use log::debug; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, FinalityNotification, @@ -53,8 +52,6 @@ use std::{ /// `Initialized` event. const MAX_FINALIZED_BLOCKS: usize = 16; -use super::subscription::InsertedSubscriptionData; - /// Generates the events of the `chainHead_follow` method. pub struct ChainHeadFollower, Block: BlockT, Client> { /// Substrate client. @@ -71,9 +68,76 @@ pub struct ChainHeadFollower, Block: BlockT, Client> { current_best_block: Option, /// LRU cache of pruned blocks. pruned_blocks: LruMap, + /// LRU cache of announced blocks. + announced_blocks: AnnouncedBlocks, /// Stop all subscriptions if the distance between the leaves and the current finalized /// block is larger than this value. max_lagging_distance: usize, + /// The maximum number of pending messages per subscription. + pub subscription_buffer_cap: usize, +} + +struct AnnouncedBlocks { + /// Unfinalized blocks. + blocks: LruMap, + /// Finalized blocks. + finalized: MostRecentFinalizedBlocks, +} + +/// Wrapper over LRU to efficiently lookup hashes and remove elements as FIFO queue. +/// +/// For the finalized blocks we use `peek` to avoid moving the block counter to the front. +/// This effectively means that the LRU acts as a FIFO queue. Otherwise, we might +/// end up with scenarios where the "finalized block" in the end of LRU is overwritten which +/// may not necessarily be the oldest finalized block i.e, possible that "get" promotes an +/// older finalized block because it was accessed more recently. +struct MostRecentFinalizedBlocks(LruMap); + +impl MostRecentFinalizedBlocks { + /// Insert the finalized block hash into the LRU cache. + fn insert(&mut self, block: Block::Hash) { + self.0.insert(block, ()); + } + + /// Check if the block is contained in the LRU cache. + fn contains(&mut self, block: &Block::Hash) -> Option<&()> { + self.0.peek(block) + } +} + +impl AnnouncedBlocks { + /// Creates a new `AnnouncedBlocks`. + fn new() -> Self { + Self { + // The total number of pinned blocks is `MAX_PINNED_BLOCKS`, ensure we don't + // exceed the limit. + blocks: LruMap::new(ByLength::new((MAX_PINNED_BLOCKS - MAX_FINALIZED_BLOCKS) as u32)), + // We are keeping a smaller number of announced finalized blocks in memory. + // This is because the `Finalized` event might be triggered before the `NewBlock` event. + finalized: MostRecentFinalizedBlocks(LruMap::new(ByLength::new( + MAX_FINALIZED_BLOCKS as u32, + ))), + } + } + + /// Insert the block into the announced blocks. + fn insert(&mut self, block: Block::Hash, finalized: bool) { + if finalized { + // When a block is declared as finalized, it is removed from the unfinalized blocks. + // + // Given that the finalized blocks are bounded to `MAX_FINALIZED_BLOCKS`, + // this ensures we keep the minimum number of blocks in memory. + self.blocks.remove(&block); + self.finalized.insert(block); + } else { + self.blocks.insert(block, ()); + } + } + + /// Check if the block was previously announced. + fn was_announced(&mut self, block: &Block::Hash) -> bool { + self.blocks.get(block).is_some() || self.finalized.contains(block).is_some() + } } impl, Block: BlockT, Client> ChainHeadFollower { @@ -85,6 +149,7 @@ impl, Block: BlockT, Client> ChainHeadFollower Self { Self { client, @@ -96,7 +161,9 @@ impl, Block: BlockT, Client> ChainHeadFollower, startup_point: &StartupPoint, ) -> Result>, SubscriptionManagementError> { - // The block was already pinned by the initial block events or by the finalized event. - if !self.sub_handle.pin_block(&self.sub_id, notification.hash)? { - return Ok(Default::default()) - } + let block_hash = notification.hash; // Ensure we are only reporting blocks after the starting point. if *notification.header.number() < startup_point.finalized_number { return Ok(Default::default()) } - Ok(self.generate_import_events( - notification.hash, - *notification.header.parent_hash(), - notification.is_new_best, - )) + // Ensure the block can be pinned before generating the events. + if !self.sub_handle.pin_block(&self.sub_id, block_hash)? { + // The block is already pinned, this is similar to the check above. + // + // The `SubscriptionManagement` ensures the block is tracked until (short lived): + // - 2 calls to `pin_block` are made (from `Finalized` and `NewBlock` branches). + // - the block is unpinned by the user + // + // This is rather a sanity checks for edge-cases (in theory), where + // [`MAX_FINALIZED_BLOCKS` + 1] finalized events are triggered before the `NewBlock` + // event of the first `Finalized` event. + return Ok(Default::default()) + } + + if self.announced_blocks.was_announced(&block_hash) { + // Block was already reported by the finalized branch. + return Ok(Default::default()) + } + + // Double check the parent hash. If the parent hash is not reported, we have a gap. + let parent_block_hash = *notification.header.parent_hash(); + if !self.announced_blocks.was_announced(&parent_block_hash) { + // The parent block was not reported, we have a gap. + return Err(SubscriptionManagementError::Custom("Parent block was not reported".into())) + } + + self.announced_blocks.insert(block_hash, false); + Ok(self.generate_import_events(block_hash, parent_block_hash, notification.is_new_best)) } /// Generates new block events from the given finalized hashes. @@ -448,12 +551,21 @@ where return Err(SubscriptionManagementError::BlockHeaderAbsent) }; + if !self.announced_blocks.was_announced(first_header.parent_hash()) { + return Err(SubscriptionManagementError::Custom( + "Parent block was not reported for a finalized block".into(), + )); + } + let parents = std::iter::once(first_header.parent_hash()).chain(finalized_block_hashes.iter()); for (i, (hash, parent)) in finalized_block_hashes.iter().zip(parents).enumerate() { - // Check if the block was already reported and thus, is already pinned. - if !self.sub_handle.pin_block(&self.sub_id, *hash)? { - continue + // Ensure the block is pinned before generating the events. + self.sub_handle.pin_block(&self.sub_id, *hash)?; + + // Check if the block was already reported. + if self.announced_blocks.was_announced(hash) { + continue; } // Generate `NewBlock` events for all blocks beside the last block in the list @@ -461,6 +573,7 @@ where if !is_last { // Generate only the `NewBlock` event for this block. events.extend(self.generate_import_events(*hash, *parent, false)); + self.announced_blocks.insert(*hash, true); continue; } @@ -483,7 +596,8 @@ where } // Let's generate the `NewBlock` and `NewBestBlock` events for the block. - events.extend(self.generate_import_events(*hash, *parent, true)) + events.extend(self.generate_import_events(*hash, *parent, true)); + self.announced_blocks.insert(*hash, true); } Ok(events) @@ -545,6 +659,10 @@ where let pruned_block_hashes = self.get_pruned_hashes(¬ification.stale_heads, last_finalized)?; + for finalized in &finalized_block_hashes { + self.announced_blocks.insert(*finalized, true); + } + let finalized_event = FollowEvent::Finalized(Finalized { finalized_block_hashes, pruned_block_hashes: pruned_block_hashes.clone(), @@ -590,71 +708,50 @@ where async fn submit_events( &mut self, startup_point: &StartupPoint, - mut stream: EventStream, + stream: EventStream, sink: Subscription, rx_stop: oneshot::Receiver<()>, ) -> Result<(), SubscriptionManagementError> where - EventStream: Stream> + Unpin, + EventStream: Stream> + Unpin + Send, { - let mut stream_item = stream.next(); - - // The stop event can be triggered by the chainHead logic when the pinned - // block guarantee cannot be hold. Or when the client is disconnected. - let connection_closed = sink.closed(); - tokio::pin!(connection_closed); - let mut stop_event = futures_util::future::select(rx_stop, connection_closed); - - while let Either::Left((Some(event), next_stop_event)) = - futures_util::future::select(stream_item, stop_event).await - { - let events = match event { - NotificationType::InitialEvents(events) => Ok(events), - NotificationType::NewBlock(notification) => - self.handle_import_blocks(notification, &startup_point), - NotificationType::Finalized(notification) => - self.handle_finalized_blocks(notification, &startup_point), - NotificationType::MethodResponse(notification) => Ok(vec![notification]), - }; + let buffer_cap = self.subscription_buffer_cap; + // create a channel to propagate error messages + let mut handle_events = |event| match event { + NotificationType::InitialEvents(events) => Ok(events), + NotificationType::NewBlock(notification) => + self.handle_import_blocks(notification, &startup_point), + NotificationType::Finalized(notification) => + self.handle_finalized_blocks(notification, &startup_point), + NotificationType::MethodResponse(notification) => Ok(vec![notification]), + }; - let events = match events { - Ok(events) => events, - Err(err) => { - debug!( - target: LOG_TARGET, - "[follow][id={:?}] Failed to handle stream notification {:?}", - self.sub_id, - err - ); - _ = sink.send(&FollowEvent::::Stop).await; - return Err(err) - }, - }; + let stream = stream + .map(|event| handle_events(event)) + .map_ok(|items| stream::iter(items).map(Ok)) + .try_flatten(); - for event in events { - if let Err(err) = sink.send(&event).await { - // Failed to submit event. + tokio::pin!(stream); + + let sink_future = + sink.pipe_from_try_stream(stream, sc_rpc::utils::BoundedVecDeque::new(buffer_cap)); + + let result = tokio::select! { + _ = rx_stop => Ok(()), + result = sink_future => { + if let Err(ref e) = result { debug!( target: LOG_TARGET, - "[follow][id={:?}] Failed to send event {:?}", self.sub_id, err + "[follow][id={:?}] Failed to handle stream notification {:?}", + &self.sub_id, + e ); - - let _ = sink.send(&FollowEvent::::Stop).await; - // No need to propagate this error further, the client disconnected. - return Ok(()) - } + }; + result } - - stream_item = stream.next(); - stop_event = next_stop_event; - } - - // If we got here either: - // - the substrate streams have closed - // - the `Stop` receiver was triggered internally (cannot hold the pinned block guarantee) - // - the client disconnected. + }; let _ = sink.send(&FollowEvent::::Stop).await; - Ok(()) + result } /// Generate the block events for the `chainHead_follow` method. 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 44a2849d9153..c505566d887d 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -44,7 +44,7 @@ use sp_core::{ use sp_runtime::traits::Block as BlockT; use sp_version::RuntimeVersion; use std::{ - collections::{HashMap, HashSet}, + collections::{HashMap, HashSet, VecDeque}, fmt::Debug, sync::Arc, time::Duration, @@ -86,6 +86,7 @@ pub async fn run_server() -> std::net::SocketAddr { subscription_max_ongoing_operations: MAX_OPERATIONS, max_follow_subscriptions_per_connection: 1, max_lagging_distance: MAX_LAGGING_DISTANCE, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -147,6 +148,7 @@ async fn setup_api() -> ( subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -254,6 +256,7 @@ async fn follow_subscription_produces_blocks() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -323,6 +326,7 @@ async fn follow_with_runtime() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -631,6 +635,7 @@ async fn call_runtime_without_flag() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1290,6 +1295,7 @@ async fn separate_operation_ids_for_subscriptions() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1376,6 +1382,7 @@ async fn follow_generates_initial_blocks() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1532,6 +1539,7 @@ async fn follow_exceeding_pinned_blocks() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1609,6 +1617,7 @@ async fn follow_with_unpin() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1715,6 +1724,7 @@ async fn unpin_duplicate_hashes() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1818,6 +1828,7 @@ async fn follow_with_multiple_unpin_hashes() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -1963,6 +1974,7 @@ async fn follow_prune_best_block() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -2149,6 +2161,7 @@ async fn follow_forks_pruned_block() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -2309,6 +2322,7 @@ async fn follow_report_multiple_pruned_block() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -2555,6 +2569,7 @@ async fn pin_block_references() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -2690,6 +2705,7 @@ async fn follow_finalized_before_new_block() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -2805,6 +2821,7 @@ async fn ensure_operation_limits_works() { subscription_max_ongoing_operations: 1, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -2910,6 +2927,7 @@ async fn storage_is_backpressured() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -3047,6 +3065,7 @@ async fn stop_storage_operation() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -3344,6 +3363,7 @@ async fn chain_head_stop_all_subscriptions() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: 5, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -3557,6 +3577,7 @@ async fn chain_head_limit_reached() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: 1, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -3597,6 +3618,7 @@ async fn follow_unique_pruned_blocks() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, max_lagging_distance: MAX_LAGGING_DISTANCE, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -3766,6 +3788,7 @@ async fn follow_report_best_block_of_a_known_block() { subscription_max_ongoing_operations: MAX_OPERATIONS, max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: MAX_PINNED_BLOCKS, }, ) .into_rpc(); @@ -3965,3 +3988,123 @@ async fn follow_report_best_block_of_a_known_block() { }); assert_eq!(event, expected); } + +#[tokio::test] +async fn follow_event_with_unknown_parent() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let client_mock = Arc::new(ChainHeadMockClient::new(client.clone())); + + let api = ChainHead::new( + client_mock.clone(), + backend, + Arc::new(TokioTestExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + max_lagging_distance: MAX_LAGGING_DISTANCE, + subscription_buffer_cap: MAX_PINNED_BLOCKS, + }, + ) + .into_rpc(); + + let finalized_hash = client.info().finalized_hash; + let mut sub = api.subscribe_unbounded("chainHead_v1_follow", [false]).await.unwrap(); + // Initialized must always be reported first. + let event: FollowEvent = get_next_event(&mut sub).await; + let expected = FollowEvent::Initialized(Initialized { + finalized_block_hashes: vec![format!("{:?}", finalized_hash)], + finalized_block_runtime: None, + with_runtime: false, + }); + assert_eq!(event, expected); + + // Block tree: + // + // finalized -> (gap: block 1) -> block 2 + // + // Block 1 is not announced yet. ChainHead should report the stop + // event when encountering an unknown parent of block 2. + + // Note: `client` is used just for constructing the blocks. + // The blocks are imported to chainHead using the `client_mock`. + let block_1 = BlockBuilderBuilder::new(&*client) + .on_parent_block(client.chain_info().genesis_hash) + .with_parent_block_number(0) + .build() + .unwrap() + .build() + .unwrap() + .block; + let block_1_hash = block_1.hash(); + client.import(BlockOrigin::Own, block_1.clone()).await.unwrap(); + + let block_2 = BlockBuilderBuilder::new(&*client) + .on_parent_block(block_1_hash) + .with_parent_block_number(1) + .build() + .unwrap() + .build() + .unwrap() + .block; + client.import(BlockOrigin::Own, block_2.clone()).await.unwrap(); + + run_with_timeout(client_mock.trigger_import_stream(block_2.header)).await; + // When importing the block 2, chainHead detects a gap in our blocks and stops. + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); +} + +#[tokio::test] +async fn events_are_backpressured() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TokioTestExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + max_lagging_distance: MAX_LAGGING_DISTANCE, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + subscription_buffer_cap: 10, + }, + ) + .into_rpc(); + + let mut parent_hash = client.chain_info().genesis_hash; + let mut header = VecDeque::new(); + let mut sub = api.subscribe("chainHead_v1_follow", [false], 1).await.unwrap(); + + // insert more events than the user can consume + for i in 0..=5 { + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(i) + .build() + .unwrap() + .build() + .unwrap() + .block; + header.push_front(block.header().clone()); + + parent_hash = block.hash(); + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + } + + let mut events = Vec::new(); + + while let Some(event) = sub.next::>().await { + events.push(event); + } + + assert_eq!(events.len(), 2); + assert_matches!(events.pop().unwrap().map(|x| x.0), Ok(FollowEvent::Stop)); +} 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 aa8ac572dec9..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,18 +16,18 @@ // 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, NumberFor}; +use sp_runtime::traits::Block as BlockT; use std::{collections::HashMap, pin::Pin, sync::Arc}; use substrate_test_runtime_transaction_pool::TestApi; use tokio::sync::mpsc; @@ -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: NumberFor, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send, - >, - > { - self.inner_pool.ready_at(at) + at: ::Hash, + ) -> Box> + Send> { + self.inner_pool.ready_at(at).await } fn ready(&self) -> Box> + Send> { @@ -184,4 +175,12 @@ impl TransactionPool for MiddlewarePool { fn futures(&self) -> Vec { self.inner_pool.futures() } + + async fn ready_at_with_timeout( + &self, + at: ::Hash, + _timeout: std::time::Duration, + ) -> Box> + Send> { + self.inner_pool.ready_at(at).await + } } 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 bde60960eaf4..ab0b8bdab699 100644 --- a/substrate/client/rpc/src/author/tests.rs +++ b/substrate/client/rpc/src/author/tests.rs @@ -66,8 +66,13 @@ impl Default for TestSetup { let client = Arc::new(substrate_test_runtime_client::TestClientBuilder::new().build()); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); TestSetup { client, keystore, pool } } } diff --git a/substrate/client/rpc/src/utils.rs b/substrate/client/rpc/src/utils.rs index e2ff04c0baf3..b94f062cddab 100644 --- a/substrate/client/rpc/src/utils.rs +++ b/substrate/client/rpc/src/utils.rs @@ -21,7 +21,7 @@ use crate::SubscriptionTaskExecutor; use futures::{ future::{self, Either, Fuse, FusedFuture}, - Future, FutureExt, Stream, StreamExt, + Future, FutureExt, Stream, StreamExt, TryStream, TryStreamExt, }; use jsonrpsee::{ types::SubscriptionId, DisconnectError, PendingSubscriptionSink, SubscriptionMessage, @@ -173,14 +173,27 @@ impl From for Subscription { impl Subscription { /// Feed items to the subscription from the underlying stream /// with specified buffer strategy. - pub async fn pipe_from_stream(self, mut stream: S, mut buf: B) + pub async fn pipe_from_stream(&self, stream: S, buf: B) where - S: Stream + Unpin + Send + 'static, - T: Serialize + Send + 'static, + S: Stream + Unpin, + T: Serialize + Send, + B: Buffer, + { + self.pipe_from_try_stream(stream.map(Ok::), buf) + .await + .expect("No Err will be ever encountered.qed"); + } + + /// Feed items to the subscription from the underlying stream + /// with specified buffer strategy. + pub async fn pipe_from_try_stream(&self, mut stream: S, mut buf: B) -> Result<(), E> + where + S: TryStream + Unpin, + T: Serialize + Send, B: Buffer, { let mut next_fut = Box::pin(Fuse::terminated()); - let mut next_item = stream.next(); + let mut next_item = stream.try_next(); let closed = self.0.closed(); futures::pin_mut!(closed); @@ -201,7 +214,7 @@ impl Subscription { next_fut = Box::pin(Fuse::terminated()); }, // New item from the stream - Either::Right((Either::Right((Some(v), n)), c)) => { + Either::Right((Either::Right((Ok(Some(v)), n)), c)) => { if buf.push(v).is_err() { log::debug!( target: "rpc", @@ -209,31 +222,35 @@ impl Subscription { self.0.method_name(), self.0.connection_id().0 ); - return + return Ok(()); } next_fut = n; closed = c; - next_item = stream.next(); + next_item = stream.try_next(); }, + // Error occured while processing the stream. + // + // terminate the stream. + Either::Right((Either::Right((Err(e), _)), _)) => return Err(e), // Stream "finished". // // Process remaining items and terminate. - Either::Right((Either::Right((None, pending_fut)), _)) => { + Either::Right((Either::Right((Ok(None), pending_fut)), _)) => { if !pending_fut.is_terminated() && pending_fut.await.is_err() { - return; + return Ok(()); } while let Some(v) = buf.pop() { if self.send(&v).await.is_err() { - return; + return Ok(()); } } - return; + return Ok(()); }, // Subscription was closed. - Either::Left(_) => return, + Either::Left(_) => return Ok(()), } } } diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index f27b7ec6fbad..68ac94539df8 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::{future::ready, 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, }; @@ -780,7 +783,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 +805,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 +822,6 @@ pub fn build_network( Arc, TracingUnboundedSender>, sc_network_transactions::TransactionsHandlerController<::Hash>, - NetworkStarter, Arc>, ), Error, @@ -847,100 +849,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 +1068,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 +1083,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 +1094,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 +1120,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 +1130,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); + + 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, + ); - future.await + 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 +1282,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 +1296,6 @@ where + Send + Sync + 'static, - Net: NetworkBackend::Hash>, { if warp_sync_config.is_none() && net_config.network_config.sync_mode.is_warp() { @@ -1117,12 +1346,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 +1361,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/config.rs b/substrate/client/service/src/config.rs index 6f65c2e2d81b..fb9e9264dfe7 100644 --- a/substrate/client/service/src/config.rs +++ b/substrate/client/service/src/config.rs @@ -37,7 +37,7 @@ pub use sc_rpc_server::{ IpNetwork, RpcEndpoint, RpcMethods, SubscriptionIdProvider as RpcSubscriptionIdProvider, }; pub use sc_telemetry::TelemetryEndpoints; -pub use sc_transaction_pool::Options as TransactionPoolOptions; +pub use sc_transaction_pool::TransactionPoolOptions; use sp_core::crypto::SecretString; use std::{ io, iter, diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index b6acdb8ed002..9c01d7288a81 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -59,11 +59,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, @@ -94,11 +96,13 @@ pub use sc_network_sync::WarpSyncConfig; pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture}; pub use sc_rpc::{RandomIntegerSubscriptionId, RandomStringSubscriptionId}; pub use sc_tracing::TracingReceiver; -pub use sc_transaction_pool::Options as TransactionPoolOptions; +pub use sc_transaction_pool::TransactionPoolOptions; pub use sc_transaction_pool_api::{error::IntoPoolError, InPoolTransaction, TransactionPool}; #[doc(hidden)] pub use std::{ops::Deref, result::Result, sync::Arc}; -pub use task_manager::{SpawnTaskHandle, Task, TaskManager, TaskRegistry, DEFAULT_GROUP_NAME}; +pub use task_manager::{ + SpawnEssentialTaskHandle, SpawnTaskHandle, Task, TaskManager, TaskRegistry, DEFAULT_GROUP_NAME, +}; use tokio::runtime::Handle; const DEFAULT_PROTOCOL_ID: &str = "sup"; @@ -484,7 +488,7 @@ where .filter(|t| t.is_propagable()) .map(|t| { let hash = t.hash().clone(); - let ex: B::Extrinsic = t.data().clone(); + let ex: B::Extrinsic = (**t.data()).clone(); (hash, ex) }) .collect() @@ -523,23 +527,28 @@ where }, }; - let import_future = self.pool.submit_one( - self.client.info().best_hash, - sc_transaction_pool_api::TransactionSource::External, - uxt, - ); + let start = std::time::Instant::now(); + let pool = self.pool.clone(); + let client = self.client.clone(); Box::pin(async move { - match import_future.await { - Ok(_) => TransactionImport::NewGood, + 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:?}"); + TransactionImport::NewGood + }, Err(e) => match e.into_pool_error() { Ok(sc_transaction_pool_api::error::Error::AlreadyImported(_)) => TransactionImport::KnownGood, - Ok(e) => { - debug!("Error adding transaction to the pool: {:?}", e); - TransactionImport::Bad - }, - Err(e) => { - debug!("Error converting pool error: {}", e); + Ok(_) => TransactionImport::Bad, + Err(_) => { // it is not bad at least, just some internal node logic error, so peer is // innocent. TransactionImport::KnownGood @@ -556,7 +565,7 @@ where fn transaction(&self, hash: &H) -> Option { self.pool.ready_transaction(hash).and_then( // Only propagable transactions should be resolved for network service. - |tx| if tx.is_propagable() { Some(tx.data().clone()) } else { None }, + |tx| if tx.is_propagable() { Some((**tx.data()).clone()) } else { None }, ) } } @@ -578,8 +587,13 @@ mod tests { let (client, longest_chain) = TestClientBuilder::new().build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); let source = sp_runtime::transaction_validity::TransactionSource::External; let best = block_on(longest_chain.best_chain()).unwrap(); let transaction = Transfer { 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 98994cc742ff..d346add93a64 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -20,6 +20,8 @@ async-trait = { workspace = true } codec = { workspace = true, default-features = true } futures = { workspace = true } futures-timer = { workspace = true } +indexmap = { workspace = true } +itertools = { workspace = true } linked-hash-map = { workspace = true } log = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } @@ -36,6 +38,8 @@ 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 } +tokio = { workspace = true, default-features = true, features = ["macros", "time"] } [dev-dependencies] array-bytes = { workspace = true, default-features = true } diff --git a/substrate/client/transaction-pool/api/src/error.rs b/substrate/client/transaction-pool/api/src/error.rs index d0744bfa3e19..e81955ebe54c 100644 --- a/substrate/client/transaction-pool/api/src/error.rs +++ b/substrate/client/transaction-pool/api/src/error.rs @@ -38,7 +38,7 @@ pub enum Error { /// The transaction validity returned no "provides" tag. /// /// Such transactions are not accepted to the pool, since we use those tags - /// to define identity of transactions (occupance of the same "slot"). + /// to define identity of transactions (occupancy of the same "slot"). #[error("Transaction does not provide any tags, so the pool can't identify it")] NoTagsProvided, diff --git a/substrate/client/transaction-pool/api/src/lib.rs b/substrate/client/transaction-pool/api/src/lib.rs index 0a313c5b782d..6f771e9479bd 100644 --- a/substrate/client/transaction-pool/api/src/lib.rs +++ b/substrate/client/transaction-pool/api/src/lib.rs @@ -23,10 +23,10 @@ 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, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Member}; use std::{collections::HashMap, hash::Hash, marker::PhantomData, pin::Pin, sync::Arc}; const LOG_TARGET: &str = "txpool::api"; @@ -36,7 +36,7 @@ pub use sp_runtime::transaction_validity::{ }; /// Transaction pool status. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct PoolStatus { /// Number of transactions in the ready queue. pub ready: usize, @@ -49,7 +49,7 @@ pub struct PoolStatus { } impl PoolStatus { - /// Returns true if the are no transactions in the pool. + /// Returns true if there are no transactions in the pool. pub fn is_empty(&self) -> bool { self.ready == 0 && self.future == 0 } @@ -57,7 +57,7 @@ impl PoolStatus { /// Possible transaction status events. /// -/// This events are being emitted by `TransactionPool` watchers, +/// These events are being emitted by `TransactionPool` watchers, /// which are also exposed over RPC. /// /// The status events can be grouped based on their kinds as: @@ -144,7 +144,7 @@ pub enum TransactionStatus { /// Maximum number of finality watchers has been reached, /// old watchers are being removed. FinalityTimeout(BlockHash), - /// Transaction has been finalized by a finality-gadget, e.g GRANDPA. + /// Transaction has been finalized by a finality-gadget, e.g. GRANDPA. #[serde(with = "v1_compatible")] Finalized((BlockHash, TxIndex)), /// Transaction has been replaced in the pool, by another transaction @@ -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; @@ -245,7 +243,7 @@ pub trait TransactionPool: Send + Sync { type Hash: Hash + Eq + Member + Serialize + DeserializeOwned + Codec; /// In-pool transaction type. type InPoolTransaction: InPoolTransaction< - Transaction = TransactionFor, + Transaction = Arc>, Hash = TxHash, >; /// Error type. @@ -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 import 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: NumberFor, - ) -> Pin< - Box< - dyn Future< - Output = Box> + Send>, - > + Send, - >, - >; + at: ::Hash, + ) -> Box> + Send>; /// Get an iterator for ready transactions ordered by priority. fn ready(&self) -> Box> + Send>; @@ -321,6 +313,16 @@ pub trait TransactionPool: Send + Sync { /// Return specific ready transaction by hash, if there is one. fn ready_transaction(&self, hash: &TxHash) -> Option>; + + /// 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 (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, + ) -> Box> + Send>; } /// An iterator of ready transactions. @@ -345,6 +347,7 @@ impl ReadyTransactions for std::iter::Empty { } /// Events that the transaction pool listens for. +#[derive(Debug)] pub enum ChainEvent { /// New best block have been added to the chain. NewBestBlock { @@ -441,7 +444,7 @@ impl OffchainSubmitTransaction for TP at: ::Hash, extrinsic: ::Extrinsic, ) -> Result<(), ()> { - log::debug!( + log::trace!( target: LOG_TARGET, "(offchain call) Submitting a transaction to the pool: {:?}", extrinsic diff --git a/substrate/client/transaction-pool/benches/basics.rs b/substrate/client/transaction-pool/benches/basics.rs index 65c83f090535..0d8c1cbba9b4 100644 --- a/substrate/client/transaction-pool/benches/basics.rs +++ b/substrate/client/transaction-pool/benches/basics.rs @@ -24,6 +24,7 @@ use futures::{ future::{ready, Ready}, }; use sc_transaction_pool::*; +use sp_blockchain::HashAndNumber; use sp_crypto_hashing::blake2_256; use sp_runtime::{ generic::BlockId, @@ -64,8 +65,9 @@ impl ChainApi for TestApi { &self, at: ::Hash, _source: TransactionSource, - uxt: ::Extrinsic, + uxt: Arc<::Extrinsic>, ) -> Self::ValidationFuture { + let uxt = (*uxt).clone(); let transfer = TransferData::try_from(&uxt) .expect("uxt is expected to be bench_call (carrying TransferData)"); let nonce = transfer.nonce; @@ -89,6 +91,15 @@ impl ChainApi for TestApi { }))) } + fn validate_transaction_blocking( + &self, + _at: ::Hash, + _source: TransactionSource, + _uxt: Arc<::Extrinsic>, + ) -> sc_transaction_pool_api::error::Result { + unimplemented!(); + } + fn block_id_to_number( &self, at: &BlockId, @@ -144,6 +155,10 @@ fn bench_configured(pool: Pool, number: u64, api: Arc) { let source = TransactionSource::External; let mut futures = Vec::new(); let mut tags = Vec::new(); + let at = HashAndNumber { + hash: api.block_id_to_hash(&BlockId::Number(1)).unwrap().unwrap(), + number: 1, + }; for nonce in 1..=number { let xt = uxt(TransferData { @@ -151,15 +166,12 @@ fn bench_configured(pool: Pool, number: u64, api: Arc) { to: AccountId::from_h256(H256::from_low_u64_be(2)), amount: 5, nonce, - }); + }) + .into(); tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1)))); - futures.push(pool.submit_one( - api.block_id_to_hash(&BlockId::Number(1)).unwrap().unwrap(), - source, - xt, - )); + futures.push(pool.submit_one(&at, source, xt)); } let res = block_on(futures::future::join_all(futures.into_iter())); @@ -170,12 +182,11 @@ fn bench_configured(pool: Pool, number: u64, api: Arc) { // Prune all transactions. let block_num = 6; - block_on(pool.prune_tags( - api.block_id_to_hash(&BlockId::Number(block_num)).unwrap().unwrap(), - tags, - vec![], - )) - .expect("Prune failed"); + let at = HashAndNumber { + hash: api.block_id_to_hash(&BlockId::Number(block_num)).unwrap().unwrap(), + number: block_num, + }; + block_on(pool.prune_tags(&at, tags, vec![])); // pool is empty assert_eq!(pool.validated_pool().status().ready, 0); diff --git a/substrate/client/transaction-pool/src/builder.rs b/substrate/client/transaction-pool/src/builder.rs new file mode 100644 index 000000000000..e1fddcdd8952 --- /dev/null +++ b/substrate/client/transaction-pool/src/builder.rs @@ -0,0 +1,245 @@ +// 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 . + +//! Utility for building substrate transaction pool trait object. + +use crate::{ + common::api::FullChainApi, + fork_aware_txpool::ForkAwareTxPool as ForkAwareFullPool, + graph::{base_pool::Transaction, ChainApi, ExtrinsicFor, ExtrinsicHash, IsValidator, Options}, + single_state_txpool::BasicPool as SingleStateFullPool, + TransactionPoolWrapper, LOG_TARGET, +}; +use prometheus_endpoint::Registry as PrometheusRegistry; +use sc_transaction_pool_api::{LocalTransactionPool, MaintainedTransactionPool}; +use sp_core::traits::SpawnEssentialNamed; +use sp_runtime::traits::Block as BlockT; +use std::{marker::PhantomData, sync::Arc, time::Duration}; + +/// The type of transaction pool. +#[derive(Debug, Clone)] +pub enum TransactionPoolType { + /// Single-state transaction pool + SingleState, + /// Fork-aware transaction pool + ForkAware, +} + +/// Transaction pool options. +#[derive(Debug, Clone)] +pub struct TransactionPoolOptions { + txpool_type: TransactionPoolType, + options: Options, +} + +impl Default for TransactionPoolOptions { + fn default() -> Self { + Self { txpool_type: TransactionPoolType::SingleState, options: Default::default() } + } +} + +impl TransactionPoolOptions { + /// Creates the options for the transaction pool using given parameters. + pub fn new_with_params( + pool_limit: usize, + pool_bytes: usize, + tx_ban_seconds: Option, + txpool_type: TransactionPoolType, + is_dev: bool, + ) -> TransactionPoolOptions { + let mut options = Options::default(); + + // ready queue + options.ready.count = pool_limit; + options.ready.total_bytes = pool_bytes; + + // future queue + let factor = 10; + options.future.count = pool_limit / factor; + options.future.total_bytes = pool_bytes / factor; + + options.ban_time = if let Some(ban_seconds) = tx_ban_seconds { + Duration::from_secs(ban_seconds) + } else if is_dev { + Duration::from_secs(0) + } else { + Duration::from_secs(30 * 60) + }; + + TransactionPoolOptions { options, txpool_type } + } + + /// Creates predefined options for benchmarking + pub fn new_for_benchmarks() -> TransactionPoolOptions { + TransactionPoolOptions { + options: Options { + ready: crate::graph::base_pool::Limit { + count: 100_000, + total_bytes: 100 * 1024 * 1024, + }, + future: crate::graph::base_pool::Limit { + count: 100_000, + total_bytes: 100 * 1024 * 1024, + }, + reject_future_transactions: false, + ban_time: Duration::from_secs(30 * 60), + }, + txpool_type: TransactionPoolType::SingleState, + } + } +} + +/// `FullClientTransactionPool` is a trait that combines the functionality of +/// `MaintainedTransactionPool` and `LocalTransactionPool` for a given `Client` and `Block`. +/// +/// This trait defines the requirements for a full client transaction pool, ensuring +/// that it can handle transactions submission and maintenance. +pub trait FullClientTransactionPool: + MaintainedTransactionPool< + Block = Block, + Hash = ExtrinsicHash>, + InPoolTransaction = Transaction< + ExtrinsicHash>, + ExtrinsicFor>, + >, + Error = as ChainApi>::Error, + > + LocalTransactionPool< + Block = Block, + Hash = ExtrinsicHash>, + Error = as ChainApi>::Error, + > +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ +} + +impl FullClientTransactionPool for P +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, + P: MaintainedTransactionPool< + Block = Block, + Hash = ExtrinsicHash>, + InPoolTransaction = Transaction< + ExtrinsicHash>, + ExtrinsicFor>, + >, + Error = as ChainApi>::Error, + > + LocalTransactionPool< + Block = Block, + Hash = ExtrinsicHash>, + Error = as ChainApi>::Error, + >, +{ +} + +/// The public type alias for the actual type providing the implementation of +/// `FullClientTransactionPool` with the given `Client` and `Block` types. +/// +/// This handle abstracts away the specific type of the transaction pool. Should be used +/// externally to keep reference to transaction pool. +pub type TransactionPoolHandle = TransactionPoolWrapper; + +/// Builder allowing to create specific instance of transaction pool. +pub struct Builder<'a, Block, Client> { + options: TransactionPoolOptions, + is_validator: IsValidator, + prometheus: Option<&'a PrometheusRegistry>, + client: Arc, + spawner: Box, + _phantom: PhantomData<(Client, Block)>, +} + +impl<'a, Client, Block> Builder<'a, Block, Client> +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sc_client_api::ExecutorProvider + + sc_client_api::UsageProvider + + sp_blockchain::HeaderMetadata + + Send + + Sync + + 'static, + ::Hash: std::marker::Unpin, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + /// Creates new instance of `Builder` + pub fn new( + spawner: impl SpawnEssentialNamed + 'static, + client: Arc, + is_validator: IsValidator, + ) -> Builder<'a, Block, Client> { + Builder { + options: Default::default(), + _phantom: Default::default(), + spawner: Box::new(spawner), + client, + is_validator, + prometheus: None, + } + } + + /// Sets the options used for creating a transaction pool instance. + pub fn with_options(mut self, options: TransactionPoolOptions) -> Self { + self.options = options; + self + } + + /// Sets the prometheus endpoint used in a transaction pool instance. + pub fn with_prometheus(mut self, prometheus: Option<&'a PrometheusRegistry>) -> Self { + self.prometheus = prometheus; + self + } + + /// Creates an instance of transaction pool. + pub fn build(self) -> TransactionPoolHandle { + log::info!(target:LOG_TARGET, " creating {:?} txpool {:?}/{:?}.", self.options.txpool_type, self.options.options.ready, self.options.options.future); + TransactionPoolWrapper::(match self.options.txpool_type { + TransactionPoolType::SingleState => Box::new(SingleStateFullPool::new_full( + self.options.options, + self.is_validator, + self.prometheus, + self.spawner, + self.client, + )), + TransactionPoolType::ForkAware => Box::new(ForkAwareFullPool::new_full( + self.options.options, + self.is_validator, + self.prometheus, + self.spawner, + self.client, + )), + }) + } +} diff --git a/substrate/client/transaction-pool/src/api.rs b/substrate/client/transaction-pool/src/common/api.rs similarity index 83% rename from substrate/client/transaction-pool/src/api.rs rename to substrate/client/transaction-pool/src/common/api.rs index cccaad7c8994..e16c0f2efa51 100644 --- a/substrate/client/transaction-pool/src/api.rs +++ b/substrate/client/transaction-pool/src/common/api.rs @@ -40,18 +40,18 @@ use sp_runtime::{ }; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; -use crate::{ +use super::{ error::{self, Error}, - graph, metrics::{ApiMetrics, ApiMetricsExt}, }; +use crate::graph; /// The transaction pool logic for full client. pub struct FullChainApi { client: Arc, _marker: PhantomData, metrics: Option>, - validation_pool: Arc + Send>>>>>, + validation_pool: mpsc::Sender + Send>>>, } /// Spawn a validation task that will be used by the transaction pool to validate transactions. @@ -101,12 +101,7 @@ impl FullChainApi { spawn_validation_pool_task("transaction-pool-task-0", receiver.clone(), spawner); spawn_validation_pool_task("transaction-pool-task-1", receiver, spawner); - FullChainApi { - client, - validation_pool: Arc::new(Mutex::new(sender)), - _marker: Default::default(), - metrics, - } + FullChainApi { client, validation_pool: sender, _marker: Default::default(), metrics } } } @@ -139,25 +134,25 @@ where ) -> Self::ValidationFuture { let (tx, rx) = oneshot::channel(); let client = self.client.clone(); - let validation_pool = self.validation_pool.clone(); + let mut validation_pool = self.validation_pool.clone(); let metrics = self.metrics.clone(); async move { metrics.report(|m| m.validations_scheduled.inc()); - validation_pool - .lock() - .await - .send( - async move { - let res = validate_transaction_blocking(&*client, at, source, uxt); - let _ = tx.send(res); - metrics.report(|m| m.validations_finished.inc()); - } - .boxed(), - ) - .await - .map_err(|e| Error::RuntimeApi(format!("Validation pool down: {:?}", e)))?; + { + validation_pool + .send( + async move { + let res = validate_transaction_blocking(&*client, at, source, uxt); + let _ = tx.send(res); + metrics.report(|m| m.validations_finished.inc()); + } + .boxed(), + ) + .await + .map_err(|e| Error::RuntimeApi(format!("Validation pool down: {:?}", e)))?; + } match rx.await { Ok(r) => r, @@ -167,6 +162,18 @@ where .boxed() } + /// Validates a transaction by calling into the runtime. + /// + /// Same as `validate_transaction` but blocks the current thread when performing validation. + fn validate_transaction_blocking( + &self, + at: Block::Hash, + source: TransactionSource, + uxt: graph::ExtrinsicFor, + ) -> error::Result { + validate_transaction_blocking(&*self.client, at, source, uxt) + } + fn block_id_to_number( &self, at: &BlockId, @@ -183,7 +190,7 @@ where fn hash_and_length( &self, - ex: &graph::ExtrinsicFor, + ex: &graph::RawExtrinsicFor, ) -> (graph::ExtrinsicHash, usize) { ex.using_encoded(|x| ( as traits::Hash>::hash(x), x.len())) } @@ -222,7 +229,10 @@ where Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { - sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction"; + let s = std::time::Instant::now(); + let h = uxt.using_encoded(|x| as traits::Hash>::hash(x)); + + let result = sp_tracing::within_span!(sp_tracing::Level::TRACE, "validate_transaction"; { let runtime_api = client.runtime_api(); let api_version = sp_tracing::within_span! { sp_tracing::Level::TRACE, "check_version"; @@ -240,7 +250,7 @@ where sp_tracing::Level::TRACE, "runtime::validate_transaction"; { if api_version >= 3 { - runtime_api.validate_transaction(at, source, uxt, at) + runtime_api.validate_transaction(at, source, (*uxt).clone(), at) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { let block_number = client.to_number(&BlockId::Hash(at)) @@ -260,39 +270,17 @@ where if api_version == 2 { #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_3(at, source, uxt) + runtime_api.validate_transaction_before_version_3(at, source, (*uxt).clone()) .map_err(|e| Error::RuntimeApi(e.to_string())) } else { #[allow(deprecated)] // old validate_transaction - runtime_api.validate_transaction_before_version_2(at, uxt) + runtime_api.validate_transaction_before_version_2(at, (*uxt).clone()) .map_err(|e| Error::RuntimeApi(e.to_string())) } } }) - }) -} + }); + log::trace!(target: LOG_TARGET, "[{h:?}] validate_transaction_blocking: at:{at:?} took:{:?}", s.elapsed()); -impl FullChainApi -where - Block: BlockT, - Client: ProvideRuntimeApi - + BlockBackend - + BlockIdTo - + HeaderBackend - + HeaderMetadata, - Client: Send + Sync + 'static, - Client::Api: TaggedTransactionQueue, -{ - /// Validates a transaction by calling into the runtime, same as - /// `validate_transaction` but blocks the current thread when performing - /// validation. Only implemented for `FullChainApi` since we can call into - /// the runtime locally. - pub fn validate_transaction_blocking( - &self, - at: Block::Hash, - source: TransactionSource, - uxt: graph::ExtrinsicFor, - ) -> error::Result { - validate_transaction_blocking(&*self.client, at, source, uxt) - } + result } diff --git a/substrate/client/transaction-pool/src/enactment_state.rs b/substrate/client/transaction-pool/src/common/enactment_state.rs similarity index 94% rename from substrate/client/transaction-pool/src/enactment_state.rs rename to substrate/client/transaction-pool/src/common/enactment_state.rs index 85c572c127e8..a7eb6a3687c6 100644 --- a/substrate/client/transaction-pool/src/enactment_state.rs +++ b/substrate/client/transaction-pool/src/common/enactment_state.rs @@ -34,7 +34,7 @@ const SKIP_MAINTENANCE_THRESHOLD: u16 = 20; /// is to figure out which phases (enactment / finalization) of transaction pool /// maintenance are needed. /// -/// Given the following chain: +/// Example: given the following chain: /// /// B1-C1-D1-E1 /// / @@ -42,8 +42,8 @@ const SKIP_MAINTENANCE_THRESHOLD: u16 = 20; /// \ /// B2-C2-D2-E2 /// -/// Some scenarios and expected behavior for sequence of `NewBestBlock` (`nbb`) and `Finalized` -/// (`f`) events: +/// the list presents scenarios and expected behavior for sequence of `NewBestBlock` (`nbb`) +/// and `Finalized` (`f`) events. true/false means if enactiment is required: /// /// - `nbb(C1)`, `f(C1)` -> false (enactment was already performed in `nbb(C1))` /// - `f(C1)`, `nbb(C1)` -> false (enactment was already performed in `f(C1))` @@ -103,7 +103,7 @@ where let new_hash = event.hash(); let finalized = event.is_finalized(); - // do not proceed with txpool maintain if block distance is to high + // do not proceed with txpool maintain if block distance is too high let skip_maintenance = match (hash_to_number(new_hash), hash_to_number(self.recent_best_block)) { (Ok(Some(new)), Ok(Some(current))) => @@ -112,14 +112,14 @@ where }; if skip_maintenance { - log::debug!(target: LOG_TARGET, "skip maintain: tree_route would be too long"); + log::trace!(target: LOG_TARGET, "skip maintain: tree_route would be too long"); self.force_update(event); return Ok(EnactmentAction::Skip) } // block was already finalized if self.recent_finalized_block == new_hash { - log::debug!(target: LOG_TARGET, "handle_enactment: block already finalized"); + log::trace!(target: LOG_TARGET, "handle_enactment: block already finalized"); return Ok(EnactmentAction::Skip) } @@ -127,7 +127,7 @@ where // it instead of tree_route provided with event let tree_route = tree_route(self.recent_best_block, new_hash)?; - log::debug!( + log::trace!( target: LOG_TARGET, "resolve hash: {new_hash:?} finalized: {finalized:?} \ tree_route: (common {:?}, last {:?}) best_block: {:?} finalized_block:{:?}", @@ -141,7 +141,7 @@ where // happening if we first received a finalization event and then a new // best event for some old stale best head. if tree_route.retracted().iter().any(|x| x.hash == self.recent_finalized_block) { - log::debug!( + log::trace!( target: LOG_TARGET, "Recently finalized block {} would be retracted by ChainEvent {}, skipping", self.recent_finalized_block, @@ -180,7 +180,7 @@ where ChainEvent::NewBestBlock { hash, .. } => self.recent_best_block = *hash, ChainEvent::Finalized { hash, .. } => self.recent_finalized_block = *hash, }; - log::debug!( + log::trace!( target: LOG_TARGET, "forced update: {:?}, {:?}", self.recent_best_block, @@ -296,7 +296,7 @@ mod enactment_state_tests { use super::*; /// asserts that tree routes are equal - fn assert_treeroute_eq( + fn assert_tree_route_eq( expected: Result, String>, result: Result, String>, ) { @@ -323,56 +323,56 @@ mod enactment_state_tests { fn tree_route_mock_test_01() { let result = tree_route(b1().hash, a().hash); let expected = TreeRoute::new(vec![b1(), a()], 1); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_02() { let result = tree_route(a().hash, b1().hash); let expected = TreeRoute::new(vec![a(), b1()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_03() { let result = tree_route(a().hash, c2().hash); let expected = TreeRoute::new(vec![a(), b2(), c2()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_04() { let result = tree_route(e2().hash, a().hash); let expected = TreeRoute::new(vec![e2(), d2(), c2(), b2(), a()], 4); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_05() { let result = tree_route(d1().hash, b1().hash); let expected = TreeRoute::new(vec![d1(), c1(), b1()], 2); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_06() { let result = tree_route(d2().hash, b2().hash); let expected = TreeRoute::new(vec![d2(), c2(), b2()], 2); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_07() { let result = tree_route(b1().hash, d1().hash); let expected = TreeRoute::new(vec![b1(), c1(), d1()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_08() { let result = tree_route(b2().hash, d2().hash); let expected = TreeRoute::new(vec![b2(), c2(), d2()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] @@ -380,7 +380,7 @@ mod enactment_state_tests { let result = tree_route(e2().hash, e1().hash); let expected = TreeRoute::new(vec![e2(), d2(), c2(), b2(), a(), b1(), c1(), d1(), e1()], 4); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] @@ -388,55 +388,55 @@ mod enactment_state_tests { let result = tree_route(e1().hash, e2().hash); let expected = TreeRoute::new(vec![e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2()], 4); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_11() { let result = tree_route(b1().hash, c2().hash); let expected = TreeRoute::new(vec![b1(), a(), b2(), c2()], 1); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_12() { let result = tree_route(d2().hash, b1().hash); let expected = TreeRoute::new(vec![d2(), c2(), b2(), a(), b1()], 3); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_13() { let result = tree_route(c2().hash, e1().hash); let expected = TreeRoute::new(vec![c2(), b2(), a(), b1(), c1(), d1(), e1()], 2); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_14() { let result = tree_route(b1().hash, b1().hash); let expected = TreeRoute::new(vec![b1()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_15() { let result = tree_route(b2().hash, b2().hash); let expected = TreeRoute::new(vec![b2()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_16() { let result = tree_route(a().hash, a().hash); let expected = TreeRoute::new(vec![a()], 0); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } #[test] fn tree_route_mock_test_17() { let result = tree_route(x2().hash, b1().hash); let expected = TreeRoute::new(vec![x2(), e2(), d2(), c2(), b2(), a(), b1()], 5); - assert_treeroute_eq(result, expected); + assert_tree_route_eq(result, expected); } } diff --git a/substrate/client/transaction-pool/src/error.rs b/substrate/client/transaction-pool/src/common/error.rs similarity index 100% rename from substrate/client/transaction-pool/src/error.rs rename to substrate/client/transaction-pool/src/common/error.rs diff --git a/substrate/client/transaction-pool/src/common/log_xt.rs b/substrate/client/transaction-pool/src/common/log_xt.rs new file mode 100644 index 000000000000..6c3752c1d50e --- /dev/null +++ b/substrate/client/transaction-pool/src/common/log_xt.rs @@ -0,0 +1,54 @@ +// 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 . + +//! Utility for logging transaction collections. + +/// Logs every transaction from given `tx_collection` with given level. +macro_rules! log_xt { + (data: hash, target: $target:expr, $level:expr, $tx_collection:expr, $text_with_format:expr) => { + if log::log_enabled!(target: $target, $level) { + for tx in $tx_collection { + log::log!(target: $target, $level, $text_with_format, tx); + } + } + }; + (data: hash, target: $target:expr, $level:expr, $tx_collection:expr, $text_with_format:expr, $($arg:expr),*) => { + if log::log_enabled!(target: $target, $level) { + for tx in $tx_collection { + log::log!(target: $target, $level, $text_with_format, tx, $($arg),*); + } + } + }; + (data: tuple, target: $target:expr, $level:expr, $tx_collection:expr, $text_with_format:expr) => { + if log::log_enabled!(target: $target, $level) { + for tx in $tx_collection { + log::log!(target: $target, $level, $text_with_format, tx.0, tx.1) + } + } + }; +} + +/// Logs every transaction from given `tx_collection` with trace level. +macro_rules! log_xt_trace { + (data: $datatype:ident, target: $target:expr, $($arg:tt)+) => ($crate::common::log_xt::log_xt!(data: $datatype, target: $target, log::Level::Trace, $($arg)+)); + (target: $target:expr, $tx_collection:expr, $text_with_format:expr) => ($crate::common::log_xt::log_xt!(data: hash, target: $target, log::Level::Trace, $tx_collection, $text_with_format)); + (target: $target:expr, $tx_collection:expr, $text_with_format:expr, $($arg:expr)*) => ($crate::common::log_xt::log_xt!(data: hash, target: $target, log::Level::Trace, $tx_collection, $text_with_format, $($arg)*)); +} + +pub(crate) use log_xt; +pub(crate) use log_xt_trace; diff --git a/substrate/client/transaction-pool/src/metrics.rs b/substrate/client/transaction-pool/src/common/metrics.rs similarity index 58% rename from substrate/client/transaction-pool/src/metrics.rs rename to substrate/client/transaction-pool/src/common/metrics.rs index 170bface9647..0ec3b511fa0e 100644 --- a/substrate/client/transaction-pool/src/metrics.rs +++ b/substrate/client/transaction-pool/src/common/metrics.rs @@ -16,76 +16,52 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Transaction pool Prometheus metrics. +//! Transaction pool Prometheus metrics for implementation of Chain API. +use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use std::sync::Arc; -use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; +use crate::LOG_TARGET; -#[derive(Clone, Default)] -pub struct MetricsLink(Arc>); +/// Provides interface to register the specific metrics in the Prometheus register. +pub(crate) trait MetricsRegistrant { + /// Registers the metrics at given Prometheus registry. + fn register(registry: &Registry) -> Result, PrometheusError>; +} -impl MetricsLink { +/// Generic structure to keep a link to metrics register. +pub(crate) struct GenericMetricsLink(Arc>>); + +impl Default for GenericMetricsLink { + fn default() -> Self { + Self(Arc::from(None)) + } +} + +impl Clone for GenericMetricsLink { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl GenericMetricsLink { pub fn new(registry: Option<&Registry>) -> Self { Self(Arc::new(registry.and_then(|registry| { - Metrics::register(registry) + M::register(registry) .map_err(|err| { - log::warn!("Failed to register prometheus metrics: {}", err); + log::warn!(target: LOG_TARGET, "Failed to register prometheus metrics: {}", err); }) .ok() }))) } - pub fn report(&self, do_this: impl FnOnce(&Metrics)) { + pub fn report(&self, do_this: impl FnOnce(&M)) { if let Some(metrics) = self.0.as_ref() { - do_this(metrics); + do_this(&**metrics); } } } -/// Transaction pool Prometheus metrics. -pub struct Metrics { - pub submitted_transactions: Counter, - pub validations_invalid: Counter, - pub block_transactions_pruned: Counter, - pub block_transactions_resubmitted: Counter, -} - -impl Metrics { - pub fn register(registry: &Registry) -> Result { - Ok(Self { - submitted_transactions: register( - Counter::new( - "substrate_sub_txpool_submitted_transactions", - "Total number of transactions submitted", - )?, - registry, - )?, - validations_invalid: register( - Counter::new( - "substrate_sub_txpool_validations_invalid", - "Total number of transactions that were removed from the pool as invalid", - )?, - registry, - )?, - block_transactions_pruned: register( - Counter::new( - "substrate_sub_txpool_block_transactions_pruned", - "Total number of transactions that was requested to be pruned by block events", - )?, - registry, - )?, - block_transactions_resubmitted: register( - Counter::new( - "substrate_sub_txpool_block_transactions_resubmitted", - "Total number of transactions that was requested to be resubmitted by block events", - )?, - registry, - )?, - }) - } -} - /// Transaction pool api Prometheus metrics. pub struct ApiMetrics { pub validations_scheduled: Counter, diff --git a/substrate/client/transaction-pool/src/common/mod.rs b/substrate/client/transaction-pool/src/common/mod.rs new file mode 100644 index 000000000000..fb280e8780ad --- /dev/null +++ b/substrate/client/transaction-pool/src/common/mod.rs @@ -0,0 +1,48 @@ +// 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 . + +//! Common components re-used across different txpool implementations. + +pub(crate) mod api; +pub(crate) mod enactment_state; +pub(crate) mod error; +pub(crate) mod log_xt; +pub(crate) mod metrics; +#[cfg(test)] +pub(crate) mod tests; + +use futures::StreamExt; +use std::sync::Arc; + +/// Inform the transaction pool about imported and finalized blocks. +pub async fn notification_future(client: Arc, txpool: Arc) +where + Block: sp_runtime::traits::Block, + Client: sc_client_api::BlockchainEvents, + Pool: sc_transaction_pool_api::MaintainedTransactionPool, +{ + let import_stream = client + .import_notification_stream() + .filter_map(|n| futures::future::ready(n.try_into().ok())) + .fuse(); + let finality_stream = client.finality_notification_stream().map(Into::into).fuse(); + + futures::stream::select(import_stream, finality_stream) + .for_each(|evt| txpool.maintain(evt)) + .await +} diff --git a/substrate/client/transaction-pool/src/tests.rs b/substrate/client/transaction-pool/src/common/tests.rs similarity index 91% rename from substrate/client/transaction-pool/src/tests.rs rename to substrate/client/transaction-pool/src/common/tests.rs index 325add3fb1c5..b00cf5fbfede 100644 --- a/substrate/client/transaction-pool/src/tests.rs +++ b/substrate/client/transaction-pool/src/common/tests.rs @@ -18,11 +18,11 @@ //! Testing related primitives for internal usage in this crate. -use crate::graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool}; +use crate::graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool, RawExtrinsicFor}; use codec::Encode; use parking_lot::Mutex; use sc_transaction_pool_api::error; -use sp_blockchain::TreeRoute; +use sp_blockchain::{HashAndNumber, TreeRoute}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Hash}, @@ -58,6 +58,10 @@ impl TestApi { pub fn expect_hash_from_number(&self, n: BlockNumber) -> H256 { self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap() } + + pub fn expect_hash_and_number(&self, n: BlockNumber) -> HashAndNumber { + HashAndNumber { hash: self.expect_hash_from_number(n), number: n } + } } impl ChainApi for TestApi { @@ -73,6 +77,7 @@ impl ChainApi for TestApi { _source: TransactionSource, uxt: ExtrinsicFor, ) -> Self::ValidationFuture { + let uxt = (*uxt).clone(); self.validation_requests.lock().push(uxt.clone()); let hash = self.hash_and_length(&uxt).0; let block_number = self.block_id_to_number(&BlockId::Hash(at)).unwrap().unwrap(); @@ -151,6 +156,15 @@ impl ChainApi for TestApi { futures::future::ready(Ok(res)) } + fn validate_transaction_blocking( + &self, + _at: ::Hash, + _source: TransactionSource, + _uxt: Arc<::Extrinsic>, + ) -> error::Result { + unimplemented!(); + } + /// Returns a block number given the block id. fn block_id_to_number( &self, @@ -176,7 +190,7 @@ impl ChainApi for TestApi { } /// Hash the extrinsic. - fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (BlockHash, usize) { + fn hash_and_length(&self, uxt: &RawExtrinsicFor) -> (BlockHash, usize) { let encoded = uxt.encode(); let len = encoded.len(); (Hashing::hash(&encoded), len) 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 new file mode 100644 index 000000000000..ecae21395c91 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/dropped_watcher.rs @@ -0,0 +1,424 @@ +// 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 . + +//! Multi-view pool dropped events listener provides means to combine streams from multiple pool +//! views into a single event stream. It allows management of dropped transaction events, adding new +//! views, and removing views as needed, ensuring that transactions which are no longer referenced +//! by any view are detected and properly notified. + +use crate::{ + common::log_xt::log_xt_trace, + fork_aware_txpool::stream_map_util::next_event, + graph::{BlockHash, ChainApi, ExtrinsicHash}, + LOG_TARGET, +}; +use futures::stream::StreamExt; +use log::{debug, trace}; +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}, + fmt::{self, Debug, Formatter}, + pin::Pin, +}; +use tokio_stream::StreamMap; + +/// Dropped-logic related event from the single view. +pub type ViewStreamEvent = crate::graph::DroppedByLimitsEvent, BlockHash>; + +/// Dropped-logic stream of events coming from the single view. +type ViewStream = Pin> + Send>>; + +/// Stream of extrinsic hashes that were dropped by the views and have no references by existing +/// views. +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 +/// [`MultiViewDropWatcherContext`]. +type Controller = mpsc::TracingUnboundedSender; + +/// A type alias for a receiver used as the commands receiver in the +/// [`MultiViewDropWatcherContext`]. +type CommandReceiver = mpsc::TracingUnboundedReceiver; + +/// Commands to control the instance of dropped transactions stream [`StreamOfDropped`]. +enum Command +where + C: ChainApi, +{ + /// Adds a new stream of dropped-related events originating in a view with a specific block + /// hash + AddView(BlockHash, ViewStream), + /// Removes an existing view's stream associated with a specific block hash. + RemoveView(BlockHash), + /// Removes internal states for given extrinsic hashes. + /// + /// Intended to ba called on finalization. + RemoveFinalizedTxs(Vec>), +} + +impl Debug for Command +where + C: ChainApi, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Command::AddView(..) => write!(f, "AddView"), + Command::RemoveView(..) => write!(f, "RemoveView"), + Command::RemoveFinalizedTxs(..) => write!(f, "RemoveFinalizedTxs"), + } + } +} + +/// Manages the state and logic for handling events related to dropped transactions across multiple +/// views. +/// +/// 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 +where + C: 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>, + /// 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>, + + /// For each transaction hash we keep the set of hashes representing the views that see this + /// transaction as ready or future. + /// + /// Once transaction is dropped, dropping view is removed from the set. + transaction_states: HashMap, HashSet>>, +} + +impl MultiViewDropWatcherContext +where + C: ChainApi + 'static, + <::Block as BlockT>::Hash: Unpin, +{ + /// Processes a `ViewStreamEvent` from a specific view and updates the internal state + /// accordingly. + /// + /// If the event indicates that a transaction has been dropped and is no longer referenced by + /// any active views, the transaction hash is returned. Otherwise `None` is returned. + fn handle_event( + &mut self, + block_hash: BlockHash, + event: ViewStreamEvent, + ) -> Option> { + trace!( + target: LOG_TARGET, + "dropped_watcher: handle_event: event:{:?} views:{:?}, ", + event, + 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::Dropped | TransactionStatus::Usurped(_) => { + if let Entry::Occupied(mut views_keeping_tx_valid) = + self.transaction_states.entry(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 Some(tx_hash) + } + } else { + debug!("[{:?}] dropped_watcher: removing (non-tracked) tx", tx_hash); + return Some(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 + /// transactions. Returns a tuple containing this stream and the controller for managing + /// this stream. + fn event_stream() -> (StreamOfDropped, Controller>) { + //note: 64 allows to avoid warning messages during execution of unit tests. + const CHANNEL_SIZE: usize = 64; + let (sender, command_receiver) = sc_utils::mpsc::tracing_unbounded::>( + "tx-pool-dropped-watcher-cmd-stream", + CHANNEL_SIZE, + ); + + let ctx = Self { + stream_map: StreamMap::new(), + command_receiver, + transaction_states: Default::default(), + }; + + let stream_map = futures::stream::unfold(ctx, |mut ctx| async move { + loop { + 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); + ctx.transaction_states.iter_mut().for_each(|(_,state)| { + state.remove(&key); + }); + }, + Command::RemoveFinalizedTxs(xts) => { + log_xt_trace!(target: LOG_TARGET, xts.clone(), "[{:?}] dropped_watcher: finalized xt removed"); + xts.iter().for_each(|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)); + } + } + } + } + }) + .boxed(); + + (stream_map, sender) + } +} + +/// The controller for manipulating the state of the [`StreamOfDropped`]. +/// +/// This struct provides methods to add and remove streams associated with views to and from the +/// stream. +pub struct MultiViewDroppedWatcherController { + /// A controller allowing to update the state of the associated [`StreamOfDropped`]. + controller: Controller>, +} + +impl Clone for MultiViewDroppedWatcherController { + fn clone(&self) -> Self { + Self { controller: self.controller.clone() } + } +} + +impl MultiViewDroppedWatcherController +where + C: 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(); + (Self { controller: ctrl }, stream_map.boxed()) + } + + /// Notifies the [`StreamOfDropped`] that new view was created. + 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}"); + }); + } + + /// Notifies the [`StreamOfDropped`] that the view was destroyed and shall be removed the + /// stream map. + 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}"); + }); + } + + /// Removes status info 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_finalized_txs send message failed: {e}"); + }); + } +} + +#[cfg(test)] +mod dropped_watcher_tests { + use super::*; + use crate::common::tests::TestApi; + use futures::{stream::pending, FutureExt, StreamExt}; + use sp_core::H256; + + type MultiViewDroppedWatcher = super::MultiViewDroppedWatcherController; + + #[tokio::test] + async fn test01() { + sp_tracing::try_init_simple(); + let (watcher, output_stream) = MultiViewDroppedWatcher::new(); + + let block_hash = H256::repeat_byte(0x01); + let tx_hash = H256::repeat_byte(0x0a); + + let view_stream = futures::stream::iter(vec![ + (tx_hash, TransactionStatus::Ready), + (tx_hash, TransactionStatus::Dropped), + ]) + .boxed(); + + 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]); + } + + #[tokio::test] + async fn test02() { + sp_tracing::try_init_simple(); + let (watcher, mut output_stream) = MultiViewDroppedWatcher::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let block_hash1 = H256::repeat_byte(0x02); + let tx_hash = H256::repeat_byte(0x0a); + + let view_stream0 = futures::stream::iter(vec![(tx_hash, TransactionStatus::Future)]) + .chain(pending()) + .boxed(); + let view_stream1 = futures::stream::iter(vec![ + (tx_hash, TransactionStatus::Ready), + (tx_hash, TransactionStatus::Dropped), + ]) + .boxed(); + + watcher.add_view(block_hash0, view_stream0); + + assert!(output_stream.next().now_or_never().is_none()); + watcher.add_view(block_hash1, view_stream1); + assert!(output_stream.next().now_or_never().is_none()); + } + + #[tokio::test] + async fn test03() { + sp_tracing::try_init_simple(); + let (watcher, output_stream) = MultiViewDroppedWatcher::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let block_hash1 = H256::repeat_byte(0x02); + let tx_hash0 = H256::repeat_byte(0x0a); + let tx_hash1 = H256::repeat_byte(0x0b); + + let view_stream0 = futures::stream::iter(vec![(tx_hash0, TransactionStatus::Future)]) + .chain(pending()) + .boxed(); + let view_stream1 = futures::stream::iter(vec![ + (tx_hash1, TransactionStatus::Ready), + (tx_hash1, TransactionStatus::Dropped), + ]) + .boxed(); + + 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]); + } + + #[tokio::test] + async fn test04() { + sp_tracing::try_init_simple(); + let (watcher, mut output_stream) = MultiViewDroppedWatcher::new(); + + 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(); + let view_stream1 = futures::stream::iter(vec![ + (tx_hash, TransactionStatus::Ready), + (tx_hash, TransactionStatus::Dropped), + ]) + .boxed(); + + watcher.add_view(block_hash0, view_stream0); + assert!(output_stream.next().now_or_never().is_none()); + + 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]); + } + + #[tokio::test] + async fn test05() { + 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::InBlock((block_hash0, 0))), + ]) + .boxed(); + + watcher.add_view(block_hash1, view_stream1); + assert!(output_stream.next().now_or_never().is_none()); + assert!(output_stream.next().now_or_never().is_none()); + assert!(output_stream.next().now_or_never().is_none()); + assert!(output_stream.next().now_or_never().is_none()); + assert!(output_stream.next().now_or_never().is_none()); + + let tx_hash = H256::repeat_byte(0x0c); + let view_stream2 = futures::stream::iter(vec![ + (tx_hash, TransactionStatus::Future), + (tx_hash, TransactionStatus::Dropped), + ]) + .boxed(); + 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]); + } +} 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 new file mode 100644 index 000000000000..065d0cb3a274 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/fork_aware_txpool.rs @@ -0,0 +1,1518 @@ +// 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 . + +//! Substrate fork-aware transaction pool implementation. + +use super::{ + dropped_watcher::{MultiViewDroppedWatcherController, StreamOfDropped}, + import_notification_sink::MultiViewImportNotificationSink, + metrics::MetricsLink as PrometheusMetrics, + multi_view_listener::MultiViewListener, + tx_mem_pool::{TxInMemPool, TxMemPool, TXMEMPOOL_TRANSACTION_LIMIT_MULTIPLIER}, + view::View, + view_store::ViewStore, +}; +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}, + ReadyIteratorFor, LOG_TARGET, +}; +use async_trait::async_trait; +use futures::{ + channel::oneshot, + future::{self}, + prelude::*, + FutureExt, +}; +use parking_lot::Mutex; +use prometheus_endpoint::Registry as PrometheusRegistry; +use sc_transaction_pool_api::{ + ChainEvent, ImportNotificationStream, MaintainedTransactionPool, PoolStatus, TransactionFor, + TransactionPool, TransactionSource, TransactionStatusStreamFor, TxHash, +}; +use sp_blockchain::{HashAndNumber, TreeRoute}; +use sp_core::traits::SpawnEssentialNamed; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, NumberFor}, +}; +use std::{ + collections::{HashMap, HashSet}, + pin::Pin, + sync::Arc, + time::Instant, +}; +use tokio::select; + +/// Fork aware transaction pool task, that needs to be polled. +pub type ForkAwareTxPoolTask = Pin + Send>>; + +/// A structure that maintains a collection of pollers associated with specific block hashes +/// (views). +struct ReadyPoll +where + Block: BlockT, +{ + pollers: HashMap>>, +} + +impl ReadyPoll +where + Block: BlockT, +{ + /// Creates a new `ReadyPoll` instance with an empty collection of pollers. + fn new() -> Self { + Self { pollers: Default::default() } + } + + /// Adds a new poller for a specific block hash and returns the `Receiver` end of the created + /// oneshot channel which will be used to deliver polled result. + fn add(&mut self, at: ::Hash) -> oneshot::Receiver { + let (s, r) = oneshot::channel(); + self.pollers.entry(at).or_default().push(s); + r + } + + /// Triggers all pollers associated with a specific block by sending the polled result through + /// each oneshot channel. + /// + /// `ready_iterator` is a closure that generates the result data to be sent to the pollers. + fn trigger(&mut self, at: Block::Hash, ready_iterator: impl Fn() -> T) { + log::trace!(target: LOG_TARGET, "fatp::trigger {at:?} pending keys: {:?}", self.pollers.keys()); + let Some(pollers) = self.pollers.remove(&at) else { return }; + pollers.into_iter().for_each(|p| { + log::debug!(target: LOG_TARGET, "trigger ready signal at block {}", at); + let _ = p.send(ready_iterator()); + }); + } + + /// Removes pollers that have their oneshot channels cancelled. + fn remove_cancelled(&mut self) { + self.pollers.retain(|_, v| v.iter().any(|sender| !sender.is_canceled())); + } +} + +/// The fork-aware transaction pool. +/// +/// It keeps track of every fork and provides the set of transactions that is valid for every fork. +pub struct ForkAwareTxPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, +{ + /// The reference to the `ChainApi` provided by client/backend. + api: Arc, + + /// Intermediate buffer for the incoming transaction. + mempool: Arc>, + + /// The store for all the views. + view_store: Arc>, + + /// Utility for managing pollers of `ready_at` future. + ready_poll: Arc, Block>>>, + + /// Prometheus's metrics endpoint. + metrics: PrometheusMetrics, + + /// Util tracking best and finalized block. + enactment_state: Arc>>, + + /// The channel allowing to send revalidation jobs to the background thread. + revalidation_queue: Arc>, + + /// Util providing an aggregated stream of transactions that were imported to ready queue in + /// any view. + import_notification_sink: MultiViewImportNotificationSink>, + + /// Externally provided pool options. + options: Options, + + /// Is node the validator. + is_validator: IsValidator, +} + +impl ForkAwareTxPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, + ::Hash: Unpin, +{ + /// Create new fork aware transaction pool with provided shared instance of `ChainApi` intended + /// for tests. + pub fn new_test( + pool_api: Arc, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + ) -> (Self, ForkAwareTxPoolTask) { + Self::new_test_with_limits( + pool_api, + best_block_hash, + finalized_hash, + Options::default().ready, + Options::default().future, + usize::MAX, + ) + } + + /// Create new fork aware transaction pool with given limits and with provided shared instance + /// of `ChainApi` intended for tests. + pub fn new_test_with_limits( + pool_api: Arc, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + ready_limits: crate::PoolLimit, + future_limits: crate::PoolLimit, + mempool_max_transactions_count: usize, + ) -> (Self, ForkAwareTxPoolTask) { + let listener = Arc::from(MultiViewListener::new()); + let (import_notification_sink, import_notification_sink_task) = + MultiViewImportNotificationSink::new_with_worker(); + + let mempool = Arc::from(TxMemPool::new( + pool_api.clone(), + 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 dropped_monitor_task = Self::dropped_monitor_task( + dropped_stream, + mempool.clone(), + import_notification_sink.clone(), + ); + + let combined_tasks = async move { + tokio::select! { + _ = import_notification_sink_task => {}, + _ = dropped_monitor_task => {} + } + } + .boxed(); + + let options = Options { ready: ready_limits, future: future_limits, ..Default::default() }; + + ( + Self { + mempool, + api: pool_api.clone(), + view_store: Arc::new(ViewStore::new(pool_api, listener, dropped_stream_controller)), + ready_poll: Arc::from(Mutex::from(ReadyPoll::new())), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), + revalidation_queue: Arc::from(revalidation_worker::RevalidationQueue::new()), + import_notification_sink, + options, + is_validator: false.into(), + metrics: Default::default(), + }, + combined_tasks, + ) + } + + /// Monitors the stream of dropped transactions and removes them from the mempool. + /// + /// 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. + async fn dropped_monitor_task( + mut dropped_stream: StreamOfDropped, + mempool: Arc>, + import_notification_sink: MultiViewImportNotificationSink< + Block::Hash, + ExtrinsicHash, + >, + ) { + loop { + let Some(dropped) = dropped_stream.next().await else { + 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]); + } + } + + /// Creates new fork aware transaction pool with the background revalidation worker. + /// + /// The txpool essential tasks (including a revalidation worker) are spawned using provided + /// spawner. + pub fn new_with_background_worker( + options: Options, + is_validator: IsValidator, + pool_api: Arc, + prometheus: Option<&PrometheusRegistry>, + spawner: impl SpawnEssentialNamed, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + ) -> Self { + let metrics = PrometheusMetrics::new(prometheus); + let listener = Arc::from(MultiViewListener::new()); + let (revalidation_queue, revalidation_task) = + revalidation_worker::RevalidationQueue::new_with_worker(); + + let (import_notification_sink, import_notification_sink_task) = + MultiViewImportNotificationSink::new_with_worker(); + + let mempool = Arc::from(TxMemPool::new( + pool_api.clone(), + 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 dropped_monitor_task = Self::dropped_monitor_task( + dropped_stream, + mempool.clone(), + import_notification_sink.clone(), + ); + + let combined_tasks = async move { + tokio::select! { + _ = revalidation_task => {}, + _ = import_notification_sink_task => {}, + _ = dropped_monitor_task => {} + } + } + .boxed(); + spawner.spawn_essential("txpool-background", Some("transaction-pool"), combined_tasks); + + Self { + mempool, + api: pool_api.clone(), + view_store: Arc::new(ViewStore::new(pool_api, listener, dropped_stream_controller)), + ready_poll: Arc::from(Mutex::from(ReadyPoll::new())), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), + revalidation_queue: Arc::from(revalidation_queue), + import_notification_sink, + options, + metrics, + is_validator, + } + } + + /// Get access to the underlying api + pub fn api(&self) -> &ChainApi { + &self.api + } + + /// Provides a status for all views at the tips of the forks. + pub fn status_all(&self) -> HashMap { + self.view_store.status() + } + + /// Provides a number of views at the tips of the forks. + pub fn active_views_count(&self) -> usize { + self.view_store.active_views.read().len() + } + + /// Provides a number of views at the tips of the forks. + pub fn inactive_views_count(&self) -> usize { + self.view_store.inactive_views.read().len() + } + + /// Provides internal views statistics. + /// + /// Provides block number, count of ready, count of future transactions for every view. It is + /// suitable for printing log information. + fn views_stats(&self) -> Vec<(NumberFor, usize, usize)> { + self.view_store + .active_views + .read() + .iter() + .map(|v| (v.1.at.number, v.1.status().ready, v.1.status().future)) + .collect() + } + + /// Checks if there is a view at the tip of the fork with given hash. + pub fn has_view(&self, hash: &Block::Hash) -> bool { + self.view_store.active_views.read().contains_key(hash) + } + + /// Returns a number of unwatched and watched transactions in internal mempool. + /// + /// Intended for use in unit tests. + pub fn mempool_len(&self) -> (usize, usize) { + self.mempool.unwatched_and_watched_count() + } + + /// Returns a best-effort set of ready transactions for a given block, without executing full + /// maintain process. + /// + /// The method attempts to build a temporary view and create an iterator of ready transactions + /// for a specific `at` hash. If a valid view is found, it collects and prunes + /// transactions already included in the blocks and returns the valid set. + /// + /// Pruning is just rebuilding the underlying transactions graph, no validations are executed, + /// so this process shall be fast. + 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 { + return Box::new(std::iter::empty()) + }; + + let best_result = { + api.tree_route(self.enactment_state.lock().recent_finalized_block(), at).map( + |tree_route| { + if let Some((index, view)) = + tree_route.enacted().iter().enumerate().rev().skip(1).find_map(|(i, b)| { + self.view_store.get_view_at(b.hash, true).map(|(view, _)| (i, view)) + }) { + let e = tree_route.enacted()[index..].to_vec(); + (TreeRoute::new(e, 0).ok(), Some(view)) + } else { + (None, None) + } + }, + ) + }; + + 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 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. + /// + /// This method combines two futures: + /// - The `ready_at` future, which waits for the ready transactions resulting from the full + /// maintenance process to be available. + /// - The `ready_at_light` future, used as a fallback if the timeout expires before `ready_at` + /// completes. This provides a best-effort, ready set of transactions as a result light + /// maintain. + /// + /// Returns a future resolving to a ready iterator of transactions. + async fn ready_at_with_timeout_internal( + &self, + at: Block::Hash, + timeout: std::time::Duration, + ) -> 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.await; + } + + let maybe_ready = async move { + select! { + ready = ready_at => Some(ready), + _ = timeout => { + log::warn!(target: LOG_TARGET, + "Timeout fired waiting for transaction pool at block: ({:?}). \ + Proceeding with production.", + at, + ); + None + } + } + }; + + let fall_back_ready = self.ready_at_light(at); + 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, 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_internal {at:?} (inactive:{inactive:?})"); + let iterator: ReadyIteratorFor = Box::new(view.pool.validated_pool().ready()); + return (true, async move { iterator }.boxed()); + } + + let pending = ready_poll + .add(at) + .map(|received| { + received.unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Error receiving ready-set iterator: {:?}", e); + Box::new(std::iter::empty()) + }) + }) + .boxed(); + log::debug!(target: LOG_TARGET, + "fatp::ready_at_internal {at:?} pending keys: {:?}", + ready_poll.pollers.keys() + ); + (false, pending) + } +} + +/// Converts the input view-to-statuses map into the output vector of statuses. +/// +/// The result of importing a bunch of transactions into a single view is the vector of statuses. +/// Every item represents a status for single transaction. The input is the map that associates +/// hash-views with vectors indicating the statuses of transactions imports. +/// +/// Import to multiple views result in two-dimensional array of statuses, which is provided as +/// input map. +/// +/// This function converts the map into the vec of results, according to the following rules: +/// - for given transaction if at least one status is success, then output vector contains success, +/// - if given transaction status is error for every view, then output vector contains error. +/// +/// The results for transactions are in the same order for every view. An output vector preserves +/// this order. +/// +/// ```skip +/// in: +/// view | xt0 status | xt1 status | xt2 status +/// h1 -> [ Ok(xth0), Ok(xth1), Err ] +/// h2 -> [ Ok(xth0), Err, Err ] +/// h3 -> [ Ok(xth0), Ok(xth1), Err ] +/// +/// out: +/// [ Ok(xth0), Ok(xth1), Err ] +/// ``` +fn reduce_multiview_result(input: HashMap>>) -> Vec> { + let mut values = input.values(); + let Some(first) = values.next() else { + return Default::default(); + }; + let length = first.len(); + debug_assert!(values.all(|x| length == x.len())); + + input + .into_values() + .reduce(|mut agg_results, results| { + agg_results.iter_mut().zip(results.into_iter()).for_each(|(agg_r, r)| { + if agg_r.is_err() { + *agg_r = r; + } + }); + agg_results + }) + .unwrap_or_default() +} + +#[async_trait] +impl TransactionPool for ForkAwareTxPool +where + Block: BlockT, + ChainApi: 'static + graph::ChainApi, + ::Hash: Unpin, +{ + type Block = ChainApi::Block; + type Hash = ExtrinsicHash; + type InPoolTransaction = Transaction, ExtrinsicFor>; + type Error = ChainApi::Error; + + /// Submits multiple transactions and returns a future resolving to the submission results. + /// + /// Actual transactions submission process is delegated to the `ViewStore` internal instance. + /// + /// 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. + async fn submit_at( + &self, + _: ::Hash, + source: TransactionSource, + xts: Vec>, + ) -> 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_results = self.mempool.extend_unwatched(source, &xts); + + if view_store.is_empty() { + return Ok(mempool_results) + } + + let to_be_submitted = mempool_results + .iter() + .zip(xts) + .filter_map(|(result, xt)| result.as_ref().ok().map(|_| xt)) + .collect::>(); + + self.metrics + .report(|metrics| metrics.submitted_transactions.inc_by(to_be_submitted.len() as _)); + + let mempool = self.mempool.clone(); + let results_map = view_store.submit(source, to_be_submitted.into_iter()).await; + let mut submission_results = reduce_multiview_result(results_map).into_iter(); + + Ok(mempool_results + .into_iter() + .map(|result| { + result.and_then(|xt_hash| { + submission_results + .next() + .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(xt_hash) + ) + }) + }) + .collect::>()) + } + + /// Submits a single transaction and returns a future resolving to the submission results. + /// + /// Actual transaction submission process is delegated to the `submit_at` function. + async fn submit_one( + &self, + _at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> Result, Self::Error> { + log::trace!(target: LOG_TARGET, "[{:?}] fatp::submit_one views:{}", self.tx_hash(&xt), self.active_views_count()); + 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), + } + } + + /// 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. + async fn submit_and_watch( + &self, + at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> 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 Err(e), + }; + + self.metrics.report(|metrics| metrics.submitted_transactions.inc()); + + let view_store = self.view_store.clone(); + let mempool = self.mempool.clone(); + view_store + .submit_and_watch(at, source, xt) + .await + .inspect_err(|_| mempool.remove(xt_hash)) + } + + /// Intended to remove transactions identified by the given hashes, and any dependent + /// transactions, from the pool. In current implementation this function only outputs the error. + /// Seems that API change is needed here to make this call reasonable. + // todo [#5491]: api change? we need block hash here (assuming we need it at all - could be + // useful for verification for debugging purposes). + fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { + if !hashes.is_empty() { + log::debug!(target: LOG_TARGET, "fatp::remove_invalid {}", hashes.len()); + log_xt_trace!(target:LOG_TARGET, hashes, "[{:?}] fatp::remove_invalid"); + self.metrics + .report(|metrics| metrics.removed_invalid_txs.inc_by(hashes.len() as _)); + } + Default::default() + } + + // todo [#5491]: api change? + // status(Hash) -> Option + /// Returns the pool status which includes information like the number of ready and future + /// transactions. + /// + /// Currently the status for the most recently notified best block is returned (for which + /// maintain process was accomplished). + fn status(&self) -> PoolStatus { + self.view_store + .most_recent_view + .read() + .map(|hash| self.view_store.status()[&hash].clone()) + .unwrap_or(PoolStatus { ready: 0, ready_bytes: 0, future: 0, future_bytes: 0 }) + } + + /// Return an event stream of notifications when transactions are imported to the pool. + /// + /// Consumers of this stream should use the `ready` method to actually get the + /// pending transactions in the right order. + fn import_notification_stream(&self) -> ImportNotificationStream> { + self.import_notification_sink.event_stream() + } + + /// Returns the hash of a given transaction. + fn hash_of(&self, xt: &TransactionFor) -> TxHash { + self.api().hash_and_length(xt).0 + } + + /// Notifies the pool about the broadcasting status of transactions. + fn on_broadcasted(&self, propagations: HashMap, Vec>) { + self.view_store.listener.transactions_broadcasted(propagations); + } + + /// Return specific ready transaction by hash, if there is one. + /// + /// Currently the ready transaction is returned if it exists for the most recently notified best + /// block (for which maintain process was accomplished). + // todo [#5491]: api change: we probably should have at here? + fn ready_transaction(&self, tx_hash: &TxHash) -> Option> { + let most_recent_view = self.view_store.most_recent_view.read(); + let result = most_recent_view + .map(|block_hash| self.view_store.ready_transaction(block_hash, tx_hash)) + .flatten(); + log::trace!( + target: LOG_TARGET, + "[{tx_hash:?}] ready_transaction: {} {:?}", + result.is_some(), + most_recent_view + ); + result + } + + /// Returns an iterator for ready transactions at a specific block, ordered by priority. + async fn ready_at(&self, at: ::Hash) -> ReadyIteratorFor { + let (_, result) = self.ready_at_internal(at); + result.await + } + + /// Returns an iterator for ready transactions, ordered by priority. + /// + /// Currently the set of ready transactions is returned if it exists for the most recently + /// notified best block (for which maintain process was accomplished). + fn ready(&self) -> ReadyIteratorFor { + self.view_store.ready() + } + + /// Returns a list of future transactions in the pool. + /// + /// Currently the set of future transactions is returned if it exists for the most recently + /// notified best block (for which maintain process was accomplished). + fn futures(&self) -> Vec { + self.view_store.futures() + } + + /// Returns a set of ready transactions at a given block within the specified timeout. + /// + /// If the timeout expires before the maintain process is accomplished, a best-effort + /// set of transactions is returned (refer to `ready_at_light`). + async fn ready_at_with_timeout( + &self, + at: ::Hash, + timeout: std::time::Duration, + ) -> ReadyIteratorFor { + self.ready_at_with_timeout_internal(at, timeout).await + } +} + +impl sc_transaction_pool_api::LocalTransactionPool + for ForkAwareTxPool, Block> +where + Block: BlockT, + ::Hash: Unpin, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata, + Client: Send + Sync + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + type Block = Block; + type Hash = ExtrinsicHash>; + type Error = as graph::ChainApi>::Error; + + fn submit_local( + &self, + _at: Block::Hash, + xt: sc_transaction_pool_api::LocalTransactionFor, + ) -> Result { + log::debug!(target: LOG_TARGET, "fatp::submit_local views:{}", self.active_views_count()); + let xt = Arc::from(xt); + let result = self + .mempool + .extend_unwatched(TransactionSource::Local, &[xt.clone()]) + .remove(0)?; + + self.view_store.submit_local(xt).or_else(|_| Ok(result)) + } +} + +impl ForkAwareTxPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, + ::Hash: Unpin, +{ + /// Handles a new block notification. + /// + /// It is responsible for handling a newly notified block. It executes some sanity checks, find + /// the best view to clone from and executes the new view build procedure for the notified + /// block. + /// + /// If the view is correctly created, `ready_at` pollers for this block will be triggered. + async fn handle_new_block(&self, tree_route: &TreeRoute) { + let hash_and_number = match tree_route.last() { + Some(hash_and_number) => hash_and_number, + None => { + log::warn!( + target: LOG_TARGET, + "Skipping ChainEvent - no last block in tree route {:?}", + tree_route, + ); + return + }, + }; + + if self.has_view(&hash_and_number.hash) { + log::trace!( + target: LOG_TARGET, + "view already exists for block: {:?}", + hash_and_number, + ); + return + } + + let best_view = self.view_store.find_best_view(tree_route); + let new_view = self.build_new_view(best_view, hash_and_number, tree_route).await; + + if let Some(view) = new_view { + { + let view = view.clone(); + self.ready_poll.lock().trigger(hash_and_number.hash, move || { + Box::from(view.pool.validated_pool().ready()) + }); + } + + View::start_background_revalidation(view, self.revalidation_queue.clone()).await; + } + } + + /// Builds a new view. + /// + /// If `origin_view` is provided, the new view will be cloned from it. Otherwise an empty view + /// will be created. + /// + /// The new view will be updated with transactions from the tree_route and the mempool, all + /// required events will be triggered, it will be inserted to the view store. + /// + /// This method will also update multi-view listeners with newly created view. + async fn build_new_view( + &self, + origin_view: Option>>, + at: &HashAndNumber, + tree_route: &TreeRoute, + ) -> Option>> { + log::debug!( + target: LOG_TARGET, + "build_new_view: for: {:?} from: {:?} tree_route: {:?}", + at, + origin_view.as_ref().map(|v| v.at.clone()), + tree_route + ); + let mut view = if let Some(origin_view) = origin_view { + let mut view = View::new_from_other(&origin_view, at); + if !tree_route.retracted().is_empty() { + view.pool.clear_recently_pruned(); + } + view + } else { + log::debug!(target: LOG_TARGET, "creating non-cloned view: for: {at:?}"); + View::new( + self.api.clone(), + at.clone(), + self.options.clone(), + self.metrics.clone(), + self.is_validator.clone(), + ) + }; + + // 1. Capture all import notification from the very beginning, so first register all + //the listeners. + self.import_notification_sink.add_view( + view.at.hash, + view.pool.validated_pool().import_notification_stream().boxed(), + ); + + self.view_store.dropped_stream_controller.add_view( + view.at.hash, + view.pool.validated_pool().create_dropped_by_limits_stream().boxed(), + ); + + let start = Instant::now(); + let watched_xts = self.register_listeners(&mut view).await; + let duration = start.elapsed(); + log::debug!(target: LOG_TARGET, "register_listeners: at {at:?} took {duration:?}"); + + // 2. Handle transactions from the tree route. Pruning transactions from the view first + // will make some space for mempool transactions in case we are at the view's limits. + let start = Instant::now(); + self.update_view_with_fork(&view, tree_route, at.clone()).await; + let duration = start.elapsed(); + log::debug!(target: LOG_TARGET, "update_view_with_fork: at {at:?} took {duration:?}"); + + // 3. Finally, submit transactions from the mempool. + let start = Instant::now(); + self.update_view_with_mempool(&mut view, watched_xts).await; + let duration = start.elapsed(); + log::debug!(target: LOG_TARGET, "update_view_with_mempool: at {at:?} took {duration:?}"); + + let view = Arc::from(view); + self.view_store.insert_new_view(view.clone(), tree_route).await; + Some(view) + } + + /// Returns the list of xts included in all block ancestors, including the block itself. + /// + /// Example: for the following chain `F<-B1<-B2<-B3` xts from `F,B1,B2,B3` will be returned. + async fn extrinsics_included_since_finalized(&self, at: Block::Hash) -> HashSet> { + let start = Instant::now(); + let recent_finalized_block = self.enactment_state.lock().recent_finalized_block(); + + let Ok(tree_route) = self.api.tree_route(recent_finalized_block, at) else { + return Default::default() + }; + + let api = self.api.clone(); + let mut all_extrinsics = HashSet::new(); + + for h in tree_route.enacted().iter().rev() { + 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| self.hash_of(&t)) + .for_each(|tx_hash| { + all_extrinsics.insert(tx_hash); + }); + } + + log::debug!(target: LOG_TARGET, + "fatp::extrinsics_included_since_finalized {} from {} count: {} took:{:?}", + at, + recent_finalized_block, + all_extrinsics.len(), + start.elapsed() + ); + all_extrinsics + } + + /// For every watched transaction in the mempool registers a transaction listener in the view. + /// + /// The transaction listener for a given view is also added to multi-view listener. This allows + /// to track aggreagated progress of the transaction within the transaction pool. + /// + /// Function returns a list of currently watched transactions in the mempool. + async fn register_listeners( + &self, + view: &View, + ) -> Vec<(ExtrinsicHash, Arc>)> { + log::debug!( + target: LOG_TARGET, + "register_listeners: {:?} xts:{:?} v:{}", + view.at, + self.mempool.unwatched_and_watched_count(), + self.active_views_count() + ); + + //todo [#5495]: maybe we don't need to register listener in view? We could use + // multi_view_listener.transaction_in_block + let results = self + .mempool + .clone_watched() + .into_iter() + .map(|(tx_hash, tx)| { + let watcher = view.create_watcher(tx_hash); + let at = view.at.clone(); + async move { + log::trace!(target: LOG_TARGET, "[{:?}] adding watcher {:?}", tx_hash, at.hash); + self.view_store.listener.add_view_watcher_for_tx( + tx_hash, + at.hash, + watcher.into_stream().boxed(), + ); + (tx_hash, tx) + } + }) + .collect::>(); + + future::join_all(results).await + } + + /// 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 + /// view. + /// + /// If there are no views, and mempool transaction is reported as invalid for the given view, + /// the transaction is reported as invalid and removed from the mempool. This does not apply to + /// stale and temporarily banned transactions. + /// + /// As the listeners for watched transactions were registered at the very beginning of maintain + /// procedure (`register_listeners`), this function accepts the list of watched transactions + /// from the mempool for which listener was actually registered to avoid submit/maintain races. + async fn update_view_with_mempool( + &self, + view: &View, + watched_xts: Vec<(ExtrinsicHash, Arc>)>, + ) { + log::debug!( + target: LOG_TARGET, + "update_view_with_mempool: {:?} xts:{:?} v:{}", + view.at, + self.mempool.unwatched_and_watched_count(), + 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 + .into_iter() + .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)) + }); + + 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); + } + + log::debug!(target: LOG_TARGET, "update_view_with_mempool: at {:?} watched {}/{}", view.at.hash, watched_submitted_count, self.mempool_len().1); + + 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))); + + // 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 { + if let Err(tx_hash) = result { + self.view_store.listener.invalidate_transactions(&[tx_hash]); + self.mempool.remove(tx_hash); + } + } + } + } + + /// Updates the view with the transactions from the given tree route. + /// + /// Transactions from the retracted blocks are resubmitted to the given view. Tags for + /// transactions included in blocks on enacted fork are pruned from the provided view. + async fn update_view_with_fork( + &self, + view: &View, + tree_route: &TreeRoute, + hash_and_number: HashAndNumber, + ) { + log::debug!(target: LOG_TARGET, "update_view_with_fork tree_route: {:?} {tree_route:?}", view.at); + let api = self.api.clone(); + + // We keep track of everything we prune so that later we won't add + // transactions with those hashes from the retracted blocks. + let mut pruned_log = HashSet::>::new(); + + future::join_all( + tree_route + .enacted() + .iter() + .map(|h| crate::prune_known_txs_for_block(h, &*api, &view.pool)), + ) + .await + .into_iter() + .for_each(|enacted_log| { + pruned_log.extend(enacted_log); + }); + + //resubmit + { + let mut resubmit_transactions = Vec::new(); + + for retracted in tree_route.retracted() { + let hash = retracted.hash; + + let block_transactions = api + .block_body(hash) + .await + .unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Failed to fetch block body: {}", e); + None + }) + .unwrap_or_default() + .into_iter(); + + let mut resubmitted_to_report = 0; + + resubmit_transactions.extend( + block_transactions + .into_iter() + .map(|tx| (self.hash_of(&tx), tx)) + .filter(|(tx_hash, _)| { + let contains = pruned_log.contains(&tx_hash); + + // need to count all transactions, not just filtered, here + resubmitted_to_report += 1; + + if !contains { + log::trace!( + target: LOG_TARGET, + "[{:?}]: Resubmitting from retracted block {:?}", + tx_hash, + hash, + ); + } + !contains + }) + .map(|(tx_hash, tx)| { + //find arc if tx is known + self.mempool.get_by_hash(tx_hash).unwrap_or_else(|| Arc::from(tx)) + }), + ); + + self.metrics.report(|metrics| { + metrics.resubmitted_retracted_txs.inc_by(resubmitted_to_report) + }); + } + + 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; + } + } + + /// Executes the maintainance for the finalized event. + /// + /// Performs a house-keeping required for finalized event. This includes: + /// - executing the on finalized procedure for the view store, + /// - purging finalized transactions from the mempool and triggering mempool revalidation, + async fn handle_finalized(&self, finalized_hash: Block::Hash, tree_route: &[Block::Hash]) { + let finalized_number = self.api.block_id_to_number(&BlockId::Hash(finalized_hash)); + log::debug!(target: LOG_TARGET, "handle_finalized {finalized_number:?} tree_route: {tree_route:?} views_count:{}", self.active_views_count()); + + let finalized_xts = self.view_store.handle_finalized(finalized_hash, tree_route).await; + + self.mempool.purge_finalized_transactions(&finalized_xts).await; + self.import_notification_sink.clean_notified_items(&finalized_xts); + + self.metrics + .report(|metrics| metrics.finalized_txs.inc_by(finalized_xts.len() as _)); + + if let Ok(Some(finalized_number)) = finalized_number { + self.revalidation_queue + .revalidate_mempool( + self.mempool.clone(), + HashAndNumber { hash: finalized_hash, number: finalized_number }, + ) + .await; + } else { + log::trace!(target: LOG_TARGET, "purge_transactions_later skipped, cannot find block number {finalized_number:?}"); + } + + self.ready_poll.lock().remove_cancelled(); + log::trace!(target: LOG_TARGET, "handle_finalized after views_count:{:?}", self.active_views_count()); + } + + /// Computes a hash of the provided transaction + fn tx_hash(&self, xt: &TransactionFor) -> TxHash { + self.api.hash_and_length(xt).0 + } +} + +#[async_trait] +impl MaintainedTransactionPool for ForkAwareTxPool +where + Block: BlockT, + ChainApi: 'static + graph::ChainApi, + ::Hash: Unpin, +{ + /// Executes the maintainance for the given chain event. + async fn maintain(&self, event: ChainEvent) { + let start = Instant::now(); + log::debug!(target: LOG_TARGET, "processing event: {event:?}"); + + self.view_store.finish_background_revalidations().await; + + let prev_finalized_block = self.enactment_state.lock().recent_finalized_block(); + + let compute_tree_route = |from, to| -> Result, String> { + match self.api.tree_route(from, to) { + Ok(tree_route) => Ok(tree_route), + Err(e) => + return Err(format!( + "Error occurred while computing tree_route from {from:?} to {to:?}: {e}" + )), + } + }; + let block_id_to_number = + |hash| self.api.block_id_to_number(&BlockId::Hash(hash)).map_err(|e| format!("{}", e)); + + let result = + self.enactment_state + .lock() + .update(&event, &compute_tree_route, &block_id_to_number); + + match result { + Err(msg) => { + log::trace!(target: LOG_TARGET, "enactment_state::update error: {msg}"); + self.enactment_state.lock().force_update(&event); + }, + Ok(EnactmentAction::Skip) => return, + Ok(EnactmentAction::HandleFinalization) => { + // todo [#5492]: in some cases handle_new_block is actually needed (new_num > + // tips_of_forks) let hash = event.hash(); + // if !self.has_view(hash) { + // if let Ok(tree_route) = compute_tree_route(prev_finalized_block, hash) { + // self.handle_new_block(&tree_route).await; + // } + // } + }, + Ok(EnactmentAction::HandleEnactment(tree_route)) => { + if matches!(event, ChainEvent::Finalized { .. }) { + self.view_store.handle_pre_finalized(event.hash()).await; + }; + self.handle_new_block(&tree_route).await; + }, + }; + + match event { + ChainEvent::NewBestBlock { .. } => {}, + ChainEvent::Finalized { hash, ref tree_route } => { + self.handle_finalized(hash, tree_route).await; + + log::trace!( + target: LOG_TARGET, + "on-finalized enacted: {tree_route:?}, previously finalized: \ + {prev_finalized_block:?}", + ); + }, + } + + let maintain_duration = start.elapsed(); + + log::info!( + target: LOG_TARGET, + "maintain: txs:{:?} views:[{};{:?}] event:{event:?} took:{:?}", + self.mempool_len(), + self.active_views_count(), + self.views_stats(), + maintain_duration + ); + + self.metrics.report(|metrics| { + let (unwatched, watched) = self.mempool_len(); + let _ = ( + self.active_views_count().try_into().map(|v| metrics.active_views.set(v)), + self.inactive_views_count().try_into().map(|v| metrics.inactive_views.set(v)), + watched.try_into().map(|v| metrics.watched_txs.set(v)), + unwatched.try_into().map(|v| metrics.unwatched_txs.set(v)), + ); + metrics.maintain_duration.observe(maintain_duration.as_secs_f64()); + }); + } +} + +impl ForkAwareTxPool, Block> +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sc_client_api::ExecutorProvider + + sc_client_api::UsageProvider + + sp_blockchain::HeaderMetadata + + Send + + Sync + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, + ::Hash: std::marker::Unpin, +{ + /// Create new fork aware transaction pool for a full node with the provided api. + pub fn new_full( + options: Options, + is_validator: IsValidator, + prometheus: Option<&PrometheusRegistry>, + spawner: impl SpawnEssentialNamed, + client: Arc, + ) -> Self { + let pool_api = Arc::new(FullChainApi::new(client.clone(), prometheus, &spawner)); + let pool = Self::new_with_background_worker( + options, + is_validator, + pool_api, + prometheus, + spawner, + client.usage_info().chain.best_hash, + client.usage_info().chain.finalized_hash, + ); + + pool + } +} + +#[cfg(test)] +mod reduce_multiview_result_tests { + use super::*; + use sp_core::H256; + #[derive(Debug, PartialEq, Clone)] + enum Error { + Custom(u8), + } + + #[test] + fn empty() { + sp_tracing::try_init_simple(); + let input = HashMap::default(); + let r = reduce_multiview_result::(input); + assert!(r.is_empty()); + } + + #[test] + fn errors_only() { + sp_tracing::try_init_simple(); + let v: Vec<(H256, Vec>)> = vec![ + ( + H256::repeat_byte(0x13), + vec![ + Err(Error::Custom(10)), + Err(Error::Custom(11)), + Err(Error::Custom(12)), + Err(Error::Custom(13)), + ], + ), + ( + H256::repeat_byte(0x14), + vec![ + Err(Error::Custom(20)), + Err(Error::Custom(21)), + Err(Error::Custom(22)), + Err(Error::Custom(23)), + ], + ), + ( + H256::repeat_byte(0x15), + vec![ + Err(Error::Custom(30)), + Err(Error::Custom(31)), + Err(Error::Custom(32)), + Err(Error::Custom(33)), + ], + ), + ]; + let input = HashMap::from_iter(v.clone()); + let r = reduce_multiview_result(input); + + //order in HashMap is random, the result shall be one of: + assert!(r == v[0].1 || r == v[1].1 || r == v[2].1); + } + + #[test] + #[should_panic] + #[cfg(debug_assertions)] + fn invalid_lengths() { + sp_tracing::try_init_simple(); + let v: Vec<(H256, Vec>)> = vec![ + (H256::repeat_byte(0x13), vec![Err(Error::Custom(12)), Err(Error::Custom(13))]), + (H256::repeat_byte(0x14), vec![Err(Error::Custom(23))]), + ]; + let input = HashMap::from_iter(v); + let _ = reduce_multiview_result(input); + } + + #[test] + fn only_hashes() { + sp_tracing::try_init_simple(); + + let v: Vec<(H256, Vec>)> = vec![ + ( + H256::repeat_byte(0x13), + vec![Ok(H256::repeat_byte(0x13)), Ok(H256::repeat_byte(0x14))], + ), + ( + H256::repeat_byte(0x14), + vec![Ok(H256::repeat_byte(0x13)), Ok(H256::repeat_byte(0x14))], + ), + ]; + let input = HashMap::from_iter(v); + let r = reduce_multiview_result(input); + + assert_eq!(r, vec![Ok(H256::repeat_byte(0x13)), Ok(H256::repeat_byte(0x14))]); + } + + #[test] + fn one_view() { + sp_tracing::try_init_simple(); + let v: Vec<(H256, Vec>)> = vec![( + H256::repeat_byte(0x13), + vec![Ok(H256::repeat_byte(0x10)), Err(Error::Custom(11))], + )]; + let input = HashMap::from_iter(v); + let r = reduce_multiview_result(input); + + assert_eq!(r, vec![Ok(H256::repeat_byte(0x10)), Err(Error::Custom(11))]); + } + + #[test] + fn mix() { + sp_tracing::try_init_simple(); + let v: Vec<(H256, Vec>)> = vec![ + ( + H256::repeat_byte(0x13), + vec![ + Ok(H256::repeat_byte(0x10)), + Err(Error::Custom(11)), + Err(Error::Custom(12)), + Err(Error::Custom(33)), + ], + ), + ( + H256::repeat_byte(0x14), + vec![ + Err(Error::Custom(20)), + Ok(H256::repeat_byte(0x21)), + Err(Error::Custom(22)), + Err(Error::Custom(33)), + ], + ), + ( + H256::repeat_byte(0x15), + vec![ + Err(Error::Custom(30)), + Err(Error::Custom(31)), + Ok(H256::repeat_byte(0x32)), + Err(Error::Custom(33)), + ], + ), + ]; + let input = HashMap::from_iter(v); + let r = reduce_multiview_result(input); + + assert_eq!( + r, + vec![ + Ok(H256::repeat_byte(0x10)), + Ok(H256::repeat_byte(0x21)), + Ok(H256::repeat_byte(0x32)), + Err(Error::Custom(33)) + ] + ); + } +} 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 new file mode 100644 index 000000000000..7fbdcade63b8 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/import_notification_sink.rs @@ -0,0 +1,396 @@ +// 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 . + +//! Multi view import notification sink. This module provides a unified stream of transactions that +//! have been notified as ready by any of the active views maintained by the transaction pool. It +//! combines streams (`import_notification_stream`) from multiple views into a single stream. Events +//! coming from this stream are dynamically dispatched to many external watchers. + +use crate::{fork_aware_txpool::stream_map_util::next_event, LOG_TARGET}; +use futures::{ + channel::mpsc::{channel, Receiver as EventStream, Sender as ExternalSink}, + stream::StreamExt, + Future, FutureExt, +}; +use log::trace; +use parking_lot::RwLock; +use sc_utils::mpsc; +use std::{ + collections::HashSet, + fmt::{self, Debug, Formatter}, + hash::Hash, + pin::Pin, + sync::Arc, +}; +use tokio_stream::StreamMap; + +/// A type alias for a pinned, boxed stream of items of type `I`. +/// This alias is particularly useful for defining the types of the incoming streams from various +/// views, and is intended to build the stream of transaction hashes that become ready. +/// +/// Note: generic parameter allows better testing of all types involved. +type StreamOf = Pin + Send>>; + +/// A type alias for a tracing unbounded sender used as the command channel controller. +/// Used to send control commands to the [`AggregatedStreamContext`]. +type Controller = mpsc::TracingUnboundedSender; + +/// A type alias for a tracing unbounded receiver used as the command channel receiver. +/// Used to receive control commands in the [`AggregatedStreamContext`]. +type CommandReceiver = mpsc::TracingUnboundedReceiver; + +/// An enum representing commands that can be sent to the multi-sinks context. +/// +/// This enum contains variants that encapsulate control commands used to manage multiple streams +/// within the `AggregatedStreamContext`. +enum Command { + /// Adds a new view with a unique key and a stream of items of type `I`. + AddView(K, StreamOf), +} + +impl Debug for Command { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Command::AddView(..) => write!(f, "AddView"), + } + } +} + +/// A context used to unfold the single stream of items aggregated from the multiple +/// streams. +/// +/// The `AggregatedStreamContext` continuously monitors both the command receiver and the stream +/// map, ensuring new views can be dynamically added and events from any active view can be +/// processed. +struct AggregatedStreamContext { + /// A map of streams identified by unique keys, + stream_map: StreamMap>, + /// A receiver for handling control commands, such as adding new views. + command_receiver: CommandReceiver>, +} + +impl AggregatedStreamContext +where + K: Send + Debug + Unpin + Clone + Default + Hash + Eq + 'static, + I: Send + Sync + 'static + PartialEq + Eq + Hash + Clone + Debug, +{ + /// Creates a new aggregated stream of items and its command controller. + /// + /// This function sets up the initial context with an empty stream map. The aggregated output + /// stream of items (e.g. hashes of transactions that become ready) is unfolded. + /// + /// It returns a tuple containing the output stream and the command controller, allowing + /// external components to control this stream. + fn event_stream() -> (StreamOf, Controller>) { + let (sender, receiver) = + sc_utils::mpsc::tracing_unbounded::>("import-notification-sink", 16); + + let ctx = Self { stream_map: StreamMap::new(), command_receiver: receiver }; + + let output_stream = futures::stream::unfold(ctx, |mut ctx| async move { + loop { + tokio::select! { + biased; + cmd = ctx.command_receiver.next() => { + match cmd? { + Command::AddView(key,stream) => { + trace!(target: LOG_TARGET,"Command::AddView {key:?}"); + ctx.stream_map.insert(key,stream); + }, + } + }, + + Some(event) = next_event(&mut ctx.stream_map) => { + trace!(target: LOG_TARGET, "import_notification_sink: select_next_some -> {:?}", event); + return Some((event.1, ctx)); + } + } + } + }) + .boxed(); + + (output_stream, sender) + } +} + +/// A struct that facilitates the relaying notifications of ready transactions from multiple views +/// to many external sinks. +/// +/// `MultiViewImportNotificationSink` provides mechanisms to dynamically add new views, filter +/// notifications of imported transactions hashes and relay them to the multiple external sinks. +#[derive(Clone)] +pub struct MultiViewImportNotificationSink { + /// A controller used to send commands to the internal [`AggregatedStreamContext`]. + controller: Controller>, + /// A vector of the external sinks, each receiving a copy of the merged stream of ready + /// transaction hashes. + external_sinks: Arc>>>, + /// A set of already notified items, ensuring that each item (transaction hash) is only + /// sent out once. + already_notified_items: Arc>>, +} + +/// An asynchronous task responsible for dispatching aggregated import notifications to multiple +/// sinks (created by [`MultiViewImportNotificationSink::event_stream`]). +pub type ImportNotificationTask = Pin + Send>>; + +impl MultiViewImportNotificationSink +where + K: 'static + Clone + Send + Debug + Default + Unpin + Eq + Hash, + I: 'static + Clone + Send + Debug + Sync + PartialEq + Eq + Hash, +{ + /// Creates a new [`MultiViewImportNotificationSink`] along with its associated worker task. + /// + /// This function initializes the sink and provides the worker task that listens for events from + /// the aggregated stream, relaying them to the external sinks. The task shall be polled by + /// caller. + /// + /// Returns a tuple containing the [`MultiViewImportNotificationSink`] and the + /// [`ImportNotificationTask`]. + pub fn new_with_worker() -> (MultiViewImportNotificationSink, ImportNotificationTask) { + let (output_stream, controller) = AggregatedStreamContext::::event_stream(); + let output_stream_controller = Self { + controller, + external_sinks: Default::default(), + already_notified_items: Default::default(), + }; + let external_sinks = output_stream_controller.external_sinks.clone(); + let already_notified_items = output_stream_controller.already_notified_items.clone(); + + let import_notifcation_task = output_stream + .for_each(move |event| { + let external_sinks = external_sinks.clone(); + let already_notified_items = already_notified_items.clone(); + async move { + if already_notified_items.write().insert(event.clone()) { + external_sinks.write().retain_mut(|sink| { + trace!(target: LOG_TARGET, "[{:?}] import_sink_worker sending out imported", event); + if let Err(e) = sink.try_send(event.clone()) { + trace!(target: LOG_TARGET, "import_sink_worker sending message failed: {e}"); + false + } else { + true + } + }); + } + } + }) + .boxed(); + (output_stream_controller, import_notifcation_task) + } + + /// Adds a new stream associated with the view identified by specified key. + /// + /// The new view's stream is added to the internal aggregated stream context by sending command + /// to its `command_receiver`. + pub fn add_view(&self, key: K, view: StreamOf) { + let _ = self + .controller + .unbounded_send(Command::AddView(key.clone(), view)) + .map_err(|e| { + trace!(target: LOG_TARGET, "add_view {key:?} send message failed: {e}"); + }); + } + + /// Creates and returns a new external stream of ready transactions hashes notifications. + pub fn event_stream(&self) -> EventStream { + const CHANNEL_BUFFER_SIZE: usize = 1024; + let (sender, receiver) = channel(CHANNEL_BUFFER_SIZE); + self.external_sinks.write().push(sender); + receiver + } + + /// Removes specified items from the `already_notified_items` set. + /// + /// Intended to be called once transactions are finalized. + pub fn clean_notified_items(&self, items_to_be_removed: &[I]) { + let mut already_notified_items = self.already_notified_items.write(); + items_to_be_removed.iter().for_each(|i| { + already_notified_items.remove(i); + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::time::Duration; + use tokio::task::JoinHandle; + + #[derive(Debug, Clone)] + struct Event { + delay: u64, + value: I, + } + + impl From<(u64, I)> for Event { + fn from(event: (u64, I)) -> Self { + Self { delay: event.0, value: event.1 } + } + } + + struct View { + scenario: Vec>, + sinks: Arc>>>, + } + + impl View { + fn new(scenario: Vec<(u64, I)>) -> Self { + Self { + scenario: scenario.into_iter().map(Into::into).collect(), + sinks: Default::default(), + } + } + + async fn event_stream(&self) -> EventStream { + let (sender, receiver) = channel(32); + self.sinks.write().push(sender); + receiver + } + + fn play(&mut self) -> JoinHandle<()> { + let mut scenario = self.scenario.clone(); + let sinks = self.sinks.clone(); + tokio::spawn(async move { + loop { + if scenario.is_empty() { + for sink in &mut *sinks.write() { + sink.close_channel(); + } + break; + }; + let x = scenario.remove(0); + tokio::time::sleep(Duration::from_millis(x.delay)).await; + for sink in &mut *sinks.write() { + sink.try_send(x.value.clone()).unwrap(); + } + } + }) + } + } + + #[tokio::test] + async fn deduplicating_works() { + sp_tracing::try_init_simple(); + + let (ctrl, runnable) = MultiViewImportNotificationSink::::new_with_worker(); + + let j0 = tokio::spawn(runnable); + + let stream = ctrl.event_stream(); + + let mut v1 = View::new(vec![(0, 1), (0, 2), (0, 3)]); + let mut v2 = View::new(vec![(0, 1), (0, 2), (0, 6)]); + let mut v3 = View::new(vec![(0, 1), (0, 2), (0, 3)]); + + let j1 = v1.play(); + let j2 = v2.play(); + let j3 = v3.play(); + + let o1 = v1.event_stream().await.boxed(); + let o2 = v2.event_stream().await.boxed(); + let o3 = v3.event_stream().await.boxed(); + + ctrl.add_view(1000, o1); + ctrl.add_view(2000, o2); + ctrl.add_view(3000, o3); + + let out = stream.take(4).collect::>().await; + assert!(out.iter().all(|v| vec![1, 2, 3, 6].contains(v))); + drop(ctrl); + + futures::future::join_all(vec![j0, j1, j2, j3]).await; + } + + #[tokio::test] + async fn dedup_filter_reset_works() { + sp_tracing::try_init_simple(); + + let (ctrl, runnable) = MultiViewImportNotificationSink::::new_with_worker(); + + let j0 = tokio::spawn(runnable); + + let stream = 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)]); + let mut v3 = View::new(vec![(20, 1), (20, 2), (20, 3)]); + + let j1 = v1.play(); + let j2 = v2.play(); + let j3 = v3.play(); + + let o1 = v1.event_stream().await.boxed(); + let o2 = v2.event_stream().await.boxed(); + let o3 = v3.event_stream().await.boxed(); + + 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(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; + } + + #[tokio::test] + async fn many_output_streams_are_supported() { + sp_tracing::try_init_simple(); + + let (ctrl, runnable) = MultiViewImportNotificationSink::::new_with_worker(); + + let j0 = tokio::spawn(runnable); + + let stream0 = ctrl.event_stream(); + let stream1 = ctrl.event_stream(); + + let mut v1 = View::new(vec![(0, 1), (0, 2), (0, 3)]); + let mut v2 = View::new(vec![(0, 1), (0, 2), (0, 6)]); + let mut v3 = View::new(vec![(0, 1), (0, 2), (0, 3)]); + + let j1 = v1.play(); + let j2 = v2.play(); + let j3 = v3.play(); + + let o1 = v1.event_stream().await.boxed(); + let o2 = v2.event_stream().await.boxed(); + let o3 = v3.event_stream().await.boxed(); + + ctrl.add_view(1000, o1); + ctrl.add_view(2000, o2); + ctrl.add_view(3000, o3); + + let out0 = stream0.take(4).collect::>().await; + let out1 = stream1.take(4).collect::>().await; + assert!(out0.iter().all(|v| vec![1, 2, 3, 6].contains(v))); + assert!(out1.iter().all(|v| vec![1, 2, 3, 6].contains(v))); + drop(ctrl); + + futures::future::join_all(vec![j0, j1, j2, j3]).await; + } +} diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/metrics.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/metrics.rs new file mode 100644 index 000000000000..73d45ac43051 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/metrics.rs @@ -0,0 +1,176 @@ +// 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 . + +//! Prometheus's metrics for a fork-aware transaction pool. + +use crate::common::metrics::{GenericMetricsLink, MetricsRegistrant}; +use prometheus_endpoint::{ + histogram_opts, linear_buckets, register, Counter, Gauge, Histogram, PrometheusError, Registry, + U64, +}; + +/// A helper alias for the Prometheus's metrics endpoint. +pub type MetricsLink = GenericMetricsLink; + +/// Transaction pool Prometheus metrics. +pub struct Metrics { + /// Total number of transactions submitted. + pub submitted_transactions: Counter, + /// Total number of currently maintained views. + pub active_views: Gauge, + /// Total number of current inactive views. + pub inactive_views: Gauge, + /// Total number of watched transactions in txpool. + pub watched_txs: Gauge, + /// Total number of unwatched transactions in txpool. + pub unwatched_txs: Gauge, + /// Total number of transactions reported as invalid. + pub removed_invalid_txs: Counter, + /// Total number of finalized transactions. + pub finalized_txs: Counter, + /// Histogram of maintain durations. + pub maintain_duration: Histogram, + /// Total number of transactions resubmitted from retracted forks. + pub resubmitted_retracted_txs: Counter, + /// Total number of transactions submitted from mempool to views. + pub submitted_from_mempool_txs: Counter, + /// Total number of transactions found as invalid during mempool revalidation. + pub mempool_revalidation_invalid_txs: Counter, + /// Total number of transactions found as invalid during view revalidation. + pub view_revalidation_invalid_txs: Counter, + /// Total number of valid transactions processed during view revalidation. + pub view_revalidation_resubmitted_txs: Counter, + /// Histogram of view revalidation durations. + pub view_revalidation_duration: Histogram, + /// Total number of the views created w/o cloning existing view. + pub non_cloned_views: Counter, +} + +impl MetricsRegistrant for Metrics { + fn register(registry: &Registry) -> Result, PrometheusError> { + Ok(Box::from(Self { + submitted_transactions: register( + Counter::new( + "substrate_sub_txpool_submitted_txs_total", + "Total number of transactions submitted", + )?, + registry, + )?, + active_views: register( + Gauge::new( + "substrate_sub_txpool_active_views", + "Total number of currently maintained views.", + )?, + registry, + )?, + inactive_views: register( + Gauge::new( + "substrate_sub_txpool_inactive_views", + "Total number of current inactive views.", + )?, + registry, + )?, + watched_txs: register( + Gauge::new( + "substrate_sub_txpool_watched_txs", + "Total number of watched transactions in txpool.", + )?, + registry, + )?, + unwatched_txs: register( + Gauge::new( + "substrate_sub_txpool_unwatched_txs", + "Total number of unwatched transactions in txpool.", + )?, + registry, + )?, + removed_invalid_txs: register( + Counter::new( + "substrate_sub_txpool_removed_invalid_txs_total", + "Total number of transactions reported as invalid.", + )?, + registry, + )?, + finalized_txs: register( + Counter::new( + "substrate_sub_txpool_finalized_txs_total", + "Total number of finalized transactions.", + )?, + registry, + )?, + maintain_duration: register( + Histogram::with_opts(histogram_opts!( + "substrate_sub_txpool_maintain_duration_seconds", + "Histogram of maintain durations.", + linear_buckets(0.0, 0.25, 13).unwrap() + ))?, + registry, + )?, + resubmitted_retracted_txs: register( + Counter::new( + "substrate_sub_txpool_resubmitted_retracted_txs_total", + "Total number of transactions resubmitted from retracted forks.", + )?, + registry, + )?, + submitted_from_mempool_txs: register( + Counter::new( + "substrate_sub_txpool_submitted_from_mempool_txs_total", + "Total number of transactions submitted from mempool to views.", + )?, + registry, + )?, + mempool_revalidation_invalid_txs: register( + Counter::new( + "substrate_sub_txpool_mempool_revalidation_invalid_txs_total", + "Total number of transactions found as invalid during mempool revalidation.", + )?, + registry, + )?, + view_revalidation_invalid_txs: register( + Counter::new( + "substrate_sub_txpool_view_revalidation_invalid_txs_total", + "Total number of transactions found as invalid during view revalidation.", + )?, + registry, + )?, + view_revalidation_resubmitted_txs: register( + Counter::new( + "substrate_sub_txpool_view_revalidation_resubmitted_txs_total", + "Total number of valid transactions processed during view revalidation.", + )?, + registry, + )?, + view_revalidation_duration: register( + Histogram::with_opts(histogram_opts!( + "substrate_sub_txpool_view_revalidation_duration_seconds", + "Histogram of view revalidation durations.", + linear_buckets(0.0, 0.25, 13).unwrap() + ))?, + registry, + )?, + non_cloned_views: register( + Counter::new( + "substrate_sub_txpool_non_cloned_views_total", + "Total number of the views created w/o cloning existing view.", + )?, + registry, + )?, + })) + } +} diff --git a/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs b/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs new file mode 100644 index 000000000000..5f7294a24fd7 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/mod.rs @@ -0,0 +1,376 @@ +// 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 . + +//! Substrate fork aware transaction pool implementation. +//! +//! # Top level overview. +//! This documentation provides high level overview of the main structures and the main flows within +//! the fork-aware transaction pool. +//! +//! ## Structures. +//! ### View. +//! #### Purpose. +//! The main responsibility of the [`View`] is to provide the valid set of ready transactions at +//! the given block. [`ForkAwareTxPool`] keeps the number of recent views for all the blocks +//! notified since recently finalized block. +//! +//! The views associated with blocks at the tips of the forks are actively updated with all newly +//! incoming transactions, while intermediate views are not updated (they still provide transactions +//! ready to be included at that block) due to performance reasons, since every transaction +//! submitted to the view needs to be [validated][runtime_api::validate]. +//! Building upon the older blocks happens relatively rare so this does not affect blocks filling. +//! +//! The view is wrapper around [`Pool`] and exposes its functionality, including the ability +//! of [tracking][`Watcher`] the progress of every transaction. +//! +//! #### Views: active, inactive. +//! All the views are stored in [`ViewStore`] structure. In this documentation the views at the tips +//! of the forks are referred as [`active_views`], while the intermediate views as +//! [`inactive_views`]. +//! +//! +//! #### The life cycle of the [`View`]. +//! Views are created when the new [`ChainEvent`] is notified to the pool. The view that is +//! [closest][find_best_view] to the newly notified block is chosen to clone from. Once built and +//! updated the newly created view is placed in [`active_views`]. Detailed description of view +//! creation is described in [the material to follow](#handling-the-new-best-block). When the view +//! is no longer at the tip of the forks, it is moved to the [`inactive_views`]. When the block +//! number of the view is lower then the finalized block, the view is permanently removed. +//! +//! +//! *Example*: +//! The following chain: +//! ```text +//! C2 - C3 - C4 +//! / +//! B1 +//! \ +//! B2 - B3 - B4 +//! ``` +//! and the following set of events: +//! ```text +//! New best block: B1, C3, C4, B4 +//! ``` +//! will result in the following set of views within the [`ViewStore`]: +//! ```text +//! active: C4, B4 +//! inactive: B1, C3 +//! ``` +//! Please note that views are only created for the notified blocks. +//! +//! +//! ### View store. +//! [`ViewStore`] is the helper structure that provides means to perform some actions like +//! [`submit`] or [`submit_and_watch`] on every view. It keeps track of both active and inactive +//! views. +//! +//! It also keeps tracks of the `most_recent_view` which is used to implement some methods of +//! [TransactionPool API], see [API considerations](#api-considerations) section. +//! +//! ### Multi-view listeners +//! There is a number of event streams that are provided by individual views: +//! - [transaction status][`Watcher`], +//! - [ready notification][`vp::import_notification_stream`] (see [networking +//! section](#networking)), +//! - [dropped notification][`create_dropped_by_limits_stream`]. +//! +//! These streams need to be merged into a single stream exposed by transaction pool (or used +//! internally). Those aggregators are often referred as multi-view listeners and they implement +//! stream-specific or event-specific logic. +//! +//! The most important is [`MultiViewListener`] which is owned by view store. +//! More information about it is provided in [transaction +//! route](#transaction-route-submit_and_watch) section. +//! +//! +//! ### Intermediate transactions buffer: [`TxMemPool`] +//! The main purpose of an internal [`TxMemPool`] (referred to as *mempool*) is to prevent a +//! transaction from being lost, e.g. due to race condition when the new transaction submission +//! occurs just before the new view is created. This could also happen when a transaction is invalid +//! on one fork and could be valid on another which is not yet fully processed by the maintain +//! procedure. Additionally, it allows the pool to accept transactions when no blocks have been +//! reported yet. +//! +//! Since watched and non-watched transactions require a different treatment, the *mempool* keeps a +//! track on how the transaction was submitted. The [transaction source][`TransactionSource`] used +//! to submit transactions also needs to be kept in the *mempool*. The *mempool* transaction is a +//! simple [wrapper][`TxInMemPool`] around the [`Arc`] reference to the actual extrinsic body. +//! +//! Once the view is created, all transactions from *mempool* are submitted to and validated at this +//! view. +//! +//! The *mempool* removes its transactions when they get finalized. The transactions in *mempool* +//! are also periodically verified at every finalized block and removed from the *mempool* if no +//! longer valid. This is process is called [*mempool* revalidation](#mempool-pruningrevalidation). +//! +//! ## Flows +//! +//! The transaction pool internally is executing numerous tasks. This includes handling submitted +//! transactions and tracking their progress, listening to [`ChainEvent`]s and executing the +//! maintain process, which aims to provide the set of ready transactions. On the other side +//! transaction pool provides a [`ready_at`] future that resolves to the iterator of ready +//! transactions. On top of that pool performs background revalidation jobs. +//! +//! This section provides a top level overview of all flows within the fork aware transaction pool. +//! +//! ### Transaction route: [`submit`][`api_submit`] +//! This flow is simple. Transaction is added to the mempool and if it is not rejected by it (due to +//! size limits), it is also [submitted][`submit`] into every view in [`active_views`]. +//! +//! When the newly created view does not contain this transaction yet, it is +//! [re-submitted][ForkAwareTxPool::update_view_with_mempool] from [`TxMemPool`] into this view. +//! +//! ### Transaction route: [`submit_and_watch`][`api_submit_and_watch`] +//! +//! The [`submit_and_watch`] function allows to submit the transaction and track its +//! [status][`TransactionStatus`] within the pool. Every view is providing an independent +//! [stream][`View::submit_and_watch`] of events, which needs to be merged into the single stream +//! exposed to the [external listener][`TransactionStatusStreamFor`]. For majority of events simple +//! forwarding of events would not work (e.g. we could get multiple [`Ready`] events, or [`Ready`] / +//! [`Future`] mix). Some additional stateful logic is required to filter and process the views' +//! events. It is also easier to trigger some events (e.g. [`Finalized`], [`Invalid`], and +//! [`Broadcast`]) using some side-channel and simply ignoring these events from the view. All the +//! before mentioned functionality is provided by the [`MultiViewListener`]. +//! +//! When watched transaction is submitted to the pool it is added the *mempool* with watched +//! flag. The external stream for the transaction is created in a [`MultiViewListener`]. Then +//! transaction is submitted to every active [`View`] (using +//! [`submit_and_watch`][`View::submit_and_watch`]) and the resulting +//! views' stream is connected to the [`MultiViewListener`]. +//! +//! ### Maintain +//! The transaction pool exposes the [task][`notification_future`] that listens to the +//! finalized and best block streams and executes the [`maintain`] procedure. +//! +//! The [`maintain`] is the main procedure of the transaction pool. It handles incoming +//! [`ChainEvent`]s, as described in the following two sub-sections. +//! +//! #### Handling the new (best) block +//! If the new block actually needs to be handled, the following steps are +//! executed: +//! - [find][find_best_view] the best view and clone it to [create a new +//! view][crate::ForkAwareTxPool::build_new_view], +//! - [update the view][ForkAwareTxPool::update_view_with_mempool] with the transactions from the +//! *mempool* +//! - all transactions from the *mempool* (with some obvious filtering applied) are submitted to +//! the view, +//! - for all watched transactions from the *mempool* the watcher is registered in the new view, +//! and it is connected to the multi-view-listener, +//! - [update the view][ForkAwareTxPool::update_view_with_fork] with the transactions from the [tree +//! route][`TreeRoute`] (which is computed from the recent best block to newly notified one by +//! [enactment state][`EnactmentState`] helper): +//! - resubmit the transactions from the retracted blocks, +//! - prune extrinsic from the enacted blocks, and trigger [`InBlock`] events, +//! - insert the newly created and updated view into the view store. +//! +//! +//! #### Handling the finalized block +//! The following actions are taken on every finalized block: +//! - send [`Finalized`] events for every transactions on the finalized [tree route][`TreeRoute`], +//! - remove all the views (both active and inactive) that are lower then finalized block from the +//! view store, +//! - removal of finalized transaction from the *mempool*, +//! - trigger [*mempool* background revalidation](#mempool-pruningrevalidation). +//! - clean up of multi-view listeners which is required to avoid ever-growing structures, +//! +//! ### Light maintain +//! The [maintain](#maintain) procedure can sometimes be quite heavy, and it may not be accomplished +//! within the time window expected by the block builder. On top of that block builder may want to +//! build few blocks in the raw, not giving the pool enough time to accomplish possible ongoing +//! maintain process. +//! +//! To address this, there is a [light version][`ready_at_light`] of the maintain procedure. It +//! [finds the best view][find_best_view], clones it and prunes all the transactions that were +//! included in enacted part of [tree route][`TreeRoute`] from the base view to the block at which a +//! ready iterator was requested. No new [transaction validations][runtime_api::validate] are +//! required to accomplish it. +//! +//! ### Providing ready transactions: `ready_at` +//! 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 +//! maintain](#light-maintain) is returned. Light maintain is always executed at the beginning of +//! [`ready_at_with_timeout`] to make sure that it is available w/ o additional delay. +//! +//! If the maintain process for the requested block was accomplished before the `ready_at` functions +//! are called both of them immediately provide the ready transactions iterator (which is simply +//! requested on the appropriate instance of the [`View`]). +//! +//! The little [`ReadyPoll`] helper contained within [`ForkAwareTxPool`] as ([`ready_poll`]) +//! implements the futures management. +//! +//! ### Background tasks +//! The [maintain](#maintain) procedure shall be as quick as possible, so heavy revalidation job is +//! delegated to the background worker. These includes view and *mempool* revalidation which are +//! both handled by the [`RevalidationQueue`] which simply sends revalidation requests to the +//! background thread. +//! +//! #### View revalidation +//! View revalidation is performed in the background thread. Revalidation is executed for every +//! view. All the transaction from the view are [revalidated][`view::revalidate`]. +//! +//! The fork-aware pool utilizes two threads to execute maintain and revalidation process +//! exclusively, ensuring maintain performance without overlapping with revalidation. +//! +//! The view revalidation process is [triggered][`start_background_revalidation`] at the very end of +//! the [maintain][`maintain`] process, and [stopped][`finish_background_revalidations`] at the +//! very beginning of the next maintenance execution (upon the next [`ChainEvent`] reception). The +//! results from the revalidation are immediately applied once the revalidation is +//! [terminated][crate::fork_aware_txpool::view::View::finish_revalidation]. +//! ```text +//! time: ----------------------> +//! maintenance thread: M----M------M--M-M--- +//! revalidation thread: -RRRR-RR-----RR-R-RRR +//! ``` +//! +//! #### Mempool pruning/revalidation +//! Transactions within *mempool* are constantly revalidated in the background. The +//! [revalidation][`mp::revalidate`] is performed in [batches][`batch_size`], and transactions that +//! were validated as latest, are revalidated first in the next iteration. The revalidation is +//! triggered on every finalized block. If a transaction is found to be invalid, the [`Invalid`] +//! event is sent and transaction is removed from the *mempool*. +//! +//! NOTE: There is one exception: if transaction is referenced by any view as ready, then it is +//! removed from the *mempool*, but not removed from the view. The [`Invalid`] event is not sent. +//! This case is not likely to happen, however it may need some extra attention. +//! +//! ### Networking +//! The pool is exposing [`ImportNotificationStream`][`import_notification_stream`], the dedicated +//! channel over which all ready transactions are notified. Internally this channel needs to merge +//! all ready events from every view. This functionality is implemented by +//! [`MultiViewImportNotificationSink`]. +//! +//! The networking module is utilizing this channel to receive info about new ready transactions +//! which later will be propagated over the network. On the other side, when a transaction is +//! received networking submits transaction to the pool using [`submit`][`api_submit`]. +//! +//! ### Handling invalid transactions +//! Refer to *mempool* revalidation [section](#mempool-pruningrevalidation). +//! +//! ## Pool limits +//! Every [`View`] has the [limits][`Options`] for the number or size of transactions it can hold. +//! Obviously the number of transactions in every view is not distributed equally, so some views +//! might be fully filled while others not. +//! +//! On the other hand the size of internal *mempool* shall also be capped, but transactions that are +//! still referenced by views should not be removed. +//! +//! When the [`View`] is at its limits, it can either reject the transaction during +//! submission process, or it can accept the transaction and drop different transaction which is +//! already in the pool during the [`enforce_limits`][`vp::enforce_limits`] process. +//! +//! The [`StreamOfDropped`] stream aggregating [per-view][`create_dropped_by_limits_stream`] streams +//! allows to monitor the transactions that were dropped by all the views (or dropped by some views +//! while not referenced by the others), what means that transaction can also be +//! [removed][`dropped_monitor_task`] from the *mempool*. +//! +//! +//! ## API Considerations +//! Refer to github issue: +//! +//! [`View`]: crate::fork_aware_txpool::view::View +//! [`view::revalidate`]: crate::fork_aware_txpool::view::View::revalidate +//! [`start_background_revalidation`]: crate::fork_aware_txpool::view::View::start_background_revalidation +//! [`View::submit_and_watch`]: crate::fork_aware_txpool::view::View::submit_and_watch +//! [`ViewStore`]: crate::fork_aware_txpool::view_store::ViewStore +//! [`finish_background_revalidations`]: crate::fork_aware_txpool::view_store::ViewStore::finish_background_revalidations +//! [find_best_view]: crate::fork_aware_txpool::view_store::ViewStore::find_best_view +//! [`active_views`]: crate::fork_aware_txpool::view_store::ViewStore::active_views +//! [`inactive_views`]: crate::fork_aware_txpool::view_store::ViewStore::inactive_views +//! [`TxMemPool`]: crate::fork_aware_txpool::tx_mem_pool::TxMemPool +//! [`mp::revalidate`]: crate::fork_aware_txpool::tx_mem_pool::TxMemPool::revalidate +//! [`batch_size`]: crate::fork_aware_txpool::tx_mem_pool::TXMEMPOOL_MAX_REVALIDATION_BATCH_SIZE +//! [`TxInMemPool`]: crate::fork_aware_txpool::tx_mem_pool::TxInMemPool +//! [`MultiViewListener`]: crate::fork_aware_txpool::multi_view_listener::MultiViewListener +//! [`Pool`]: crate::graph::Pool +//! [`Watcher`]: crate::graph::watcher::Watcher +//! [`Options`]: crate::graph::Options +//! [`vp::import_notification_stream`]: ../graph/validated_pool/struct.ValidatedPool.html#method.import_notification_stream +//! [`vp::enforce_limits`]: ../graph/validated_pool/struct.ValidatedPool.html#method.enforce_limits +//! [`create_dropped_by_limits_stream`]: ../graph/validated_pool/struct.ValidatedPool.html#method.create_dropped_by_limits_stream +//! [`ChainEvent`]: sc_transaction_pool_api::ChainEvent +//! [`TransactionStatusStreamFor`]: sc_transaction_pool_api::TransactionStatusStreamFor +//! [`api_submit`]: sc_transaction_pool_api::TransactionPool::submit_at +//! [`api_submit_and_watch`]: sc_transaction_pool_api::TransactionPool::submit_and_watch +//! [`ready_at_with_timeout`]: sc_transaction_pool_api::TransactionPool::ready_at_with_timeout +//! [`TransactionSource`]: sc_transaction_pool_api::TransactionSource +//! [TransactionPool API]: sc_transaction_pool_api::TransactionPool +//! [`TransactionStatus`]:sc_transaction_pool_api::TransactionStatus +//! [`Ready`]:sc_transaction_pool_api::TransactionStatus::Ready +//! [`Future`]:sc_transaction_pool_api::TransactionStatus::Future +//! [`Broadcast`]:sc_transaction_pool_api::TransactionStatus::Broadcast +//! [`Invalid`]:sc_transaction_pool_api::TransactionStatus::Invalid +//! [`InBlock`]:sc_transaction_pool_api::TransactionStatus::InBlock +//! [`Finalized`]:sc_transaction_pool_api::TransactionStatus::Finalized +//! [`ReadyTransactions`]:sc_transaction_pool_api::ReadyTransactions +//! [`dropped_monitor_task`]: ForkAwareTxPool::dropped_monitor_task +//! [`ready_poll`]: ForkAwareTxPool::ready_poll +//! [`ready_at_light`]: ForkAwareTxPool::ready_at_light +//! [`ready_at`]: ../struct.ForkAwareTxPool.html#method.ready_at +//! [`import_notification_stream`]: ../struct.ForkAwareTxPool.html#method.import_notification_stream +//! [`maintain`]: ../struct.ForkAwareTxPool.html#method.maintain +//! [`submit`]: ../struct.ForkAwareTxPool.html#method.submit_at +//! [`submit_and_watch`]: ../struct.ForkAwareTxPool.html#method.submit_and_watch +//! [`ReadyPoll`]: ../fork_aware_txpool/fork_aware_txpool/struct.ReadyPoll.html +//! [`TreeRoute`]: sp_blockchain::TreeRoute +//! [runtime_api::validate]: sp_transaction_pool::runtime_api::TaggedTransactionQueue::validate_transaction +//! [`notification_future`]: crate::common::notification_future +//! [`EnactmentState`]: crate::common::enactment_state::EnactmentState +//! [`MultiViewImportNotificationSink`]: crate::fork_aware_txpool::import_notification_sink::MultiViewImportNotificationSink +//! [`RevalidationQueue`]: crate::fork_aware_txpool::revalidation_worker::RevalidationQueue +//! [`StreamOfDropped`]: crate::fork_aware_txpool::dropped_watcher::StreamOfDropped +//! [`Arc`]: std::sync::Arc + +mod dropped_watcher; +pub(crate) mod fork_aware_txpool; +mod import_notification_sink; +mod metrics; +mod multi_view_listener; +mod revalidation_worker; +mod tx_mem_pool; +mod view; +mod view_store; + +pub use fork_aware_txpool::{ForkAwareTxPool, ForkAwareTxPoolTask}; + +mod stream_map_util { + use futures::Stream; + use std::marker::Unpin; + use tokio_stream::StreamMap; + + pub async fn next_event( + stream_map: &mut StreamMap, + ) -> Option<(K, ::Item)> + where + K: Clone + Unpin, + V: Stream + Unpin, + { + if stream_map.is_empty() { + // yield pending to prevent busy-loop on an empty map + futures::pending!() + } + + futures::StreamExt::next(stream_map).await + } +} 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 new file mode 100644 index 000000000000..8d0e69db2e9a --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/multi_view_listener.rs @@ -0,0 +1,736 @@ +// 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 . + +//! `MultiViewListener` and `ExternalWatcherContext` manage view streams and status updates for +//! transactions, providing control commands to manage transaction states, and create external +//! aggregated streams of transaction events. + +use crate::{ + fork_aware_txpool::stream_map_util::next_event, + graph::{self, BlockHash, ExtrinsicHash}, + LOG_TARGET, +}; +use futures::StreamExt; +use log::{debug, trace}; +use sc_transaction_pool_api::{TransactionStatus, TransactionStatusStream, TxIndex}; +use sc_utils::mpsc; +use sp_runtime::traits::Block as BlockT; +use std::{ + collections::{hash_map::Entry, HashMap, HashSet}, + pin::Pin, +}; +use tokio_stream::StreamMap; + +/// A side channel allowing to control the external stream instance (one per transaction) with +/// [`ControllerCommand`]. +/// +/// Set of instances of [`Controller`] lives within the [`MultiViewListener`]. +type Controller = mpsc::TracingUnboundedSender; + +/// A receiver of [`ControllerCommand`] instances allowing to control the external stream. +/// +/// Lives within the [`ExternalWatcherContext`] instance. +type CommandReceiver = mpsc::TracingUnboundedReceiver; + +/// The stream of the transaction events. +/// +/// It can represent both a single view's stream and an external watcher stream. +pub type TxStatusStream = Pin, BlockHash>>>; + +/// Commands to control the single external stream living within the multi view listener. +enum ControllerCommand { + /// Adds a new stream of transaction statuses originating in the view associated with a + /// specific block hash. + AddViewStream(BlockHash, TxStatusStream), + + /// Removes an existing view's stream associated with a specific block hash. + RemoveViewStream(BlockHash), + + /// Marks a transaction as invalidated. + /// + /// If all pre-conditions are met, an external invalid event will be sent out. + TransactionInvalidated, + + /// Notifies that a transaction was finalized in a specific block hash and transaction index. + /// + /// Send out an external finalized event. + FinalizeTransaction(BlockHash, TxIndex), + + /// Notifies that a transaction was broadcasted with a list of peer addresses. + /// + /// Sends out an external broadcasted event. + TransactionBroadcasted(Vec), + + /// Notifies that a transaction was dropped from the pool. + /// + /// If all preconditions are met, an external dropped event will be sent out. + TransactionDropped, +} + +impl std::fmt::Debug for ControllerCommand +where + ChainApi: graph::ChainApi, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ControllerCommand::AddViewStream(h, _) => write!(f, "ListenerAction::AddView({h})"), + ControllerCommand::RemoveViewStream(h) => write!(f, "ListenerAction::RemoveView({h})"), + ControllerCommand::TransactionInvalidated => { + write!(f, "ListenerAction::TransactionInvalidated") + }, + ControllerCommand::FinalizeTransaction(h, i) => { + write!(f, "ListenerAction::FinalizeTransaction({h},{i})") + }, + ControllerCommand::TransactionBroadcasted(_) => { + write!(f, "ListenerAction::TransactionBroadcasted(...)") + }, + ControllerCommand::TransactionDropped => { + write!(f, "ListenerAction::TransactionDropped") + }, + } + } +} + +/// This struct allows to create and control listener for multiple transactions. +/// +/// For every transaction the view's stream generating its own events can be added. The events are +/// flattened and sent out to the external listener. (The *external* term here means that it can be +/// exposed to [`sc_transaction_pool_api::TransactionPool`] API client e.g. over RPC.) +/// +/// The listener allows to add and remove view's stream (per transaction). +/// +/// The listener provides a side channel that allows triggering specific events (finalized, dropped, +/// invalid) independently of the view's stream. +pub struct MultiViewListener { + /// Provides the set of controllers for the events streams corresponding to individual + /// transactions identified by transaction hashes. + controllers: parking_lot::RwLock< + HashMap, Controller>>, + >, +} + +/// The external stream unfolding context. +/// +/// This context is used to unfold the external events stream for a single transaction, it +/// facilitates the logic of converting single view's events to the external events stream. +struct ExternalWatcherContext { + /// The hash of the transaction being monitored within this context. + tx_hash: ExtrinsicHash, + /// A stream map of transaction status streams coming from individual views, keyed by + /// block hash associated with view. + status_stream_map: StreamMap, TxStatusStream>, + /// A receiver for controller commands. + command_receiver: CommandReceiver>, + /// A flag indicating whether the context should terminate. + terminate: bool, + /// A flag indicating if a `Future` status has been encountered. + future_seen: bool, + /// A flag indicating if a `Ready` status has been encountered. + ready_seen: bool, + + /// A hash set of block hashes from views that consider the transaction valid. + views_keeping_tx_valid: HashSet>, +} + +impl ExternalWatcherContext +where + <::Block as BlockT>::Hash: Unpin, +{ + /// Creates new `ExternalWatcherContext` for particular transaction identified by `tx_hash` + /// + /// The `command_receiver` is a side channel for receiving controller's commands. + fn new( + tx_hash: ExtrinsicHash, + command_receiver: CommandReceiver>, + ) -> Self { + Self { + tx_hash, + status_stream_map: StreamMap::new(), + command_receiver, + terminate: false, + future_seen: false, + ready_seen: false, + views_keeping_tx_valid: Default::default(), + } + } + + /// Handles various transaction status updates and manages internal states based on the status. + /// + /// Function may set the context termination flag, which will close the stream. + /// + /// Returns `Some` with the `event` to forward or `None`. + fn handle( + &mut self, + status: TransactionStatus, BlockHash>, + hash: BlockHash, + ) -> Option, BlockHash>> { + trace!( + target: LOG_TARGET, "[{:?}] mvl handle event from {hash:?}: {status:?} views:{:?}", self.tx_hash, + self.status_stream_map.keys().collect::>() + ); + match status { + TransactionStatus::Future => { + self.views_keeping_tx_valid.insert(hash); + if self.ready_seen || self.future_seen { + None + } else { + self.future_seen = true; + Some(status) + } + }, + TransactionStatus::Ready => { + self.views_keeping_tx_valid.insert(hash); + if self.ready_seen { + None + } else { + self.ready_seen = true; + Some(status) + } + }, + TransactionStatus::Broadcast(_) => None, + TransactionStatus::InBlock((..)) => { + self.views_keeping_tx_valid.insert(hash); + if !(self.ready_seen || self.future_seen) { + self.ready_seen = true; + Some(status) + } else { + Some(status) + } + }, + TransactionStatus::Retracted(_) => None, + TransactionStatus::FinalityTimeout(_) => Some(status), + TransactionStatus::Finalized(_) => { + self.terminate = true; + Some(status) + }, + TransactionStatus::Usurped(_) | + TransactionStatus::Dropped | + TransactionStatus::Invalid => None, + } + } + + /// Handles transaction invalidation sent via side channel. + /// + /// Function may set the context termination flag, which will close the stream. + /// + /// Returns true if the event should be sent out, and false if the invalidation request should + /// be skipped. + fn handle_invalidate_transaction(&mut self) -> bool { + let keys = HashSet::>::from_iter( + self.status_stream_map.keys().map(Clone::clone), + ); + trace!( + target: LOG_TARGET, + "[{:?}] got invalidate_transaction: views:{:?}", self.tx_hash, + self.status_stream_map.keys().collect::>() + ); + if self.views_keeping_tx_valid.is_disjoint(&keys) { + self.terminate = true; + true + } else { + //todo [#5477] + // - handle corner case: this may happen when tx is invalid for mempool, but somehow + // some view still sees it as ready/future. In that case we don't send the invalid + // event, as transaction can still be included. Probably we should set some flag here + // and allow for invalid sent from the view. + // - add debug / metrics, + false + } + } + + /// Adds a new transaction status stream. + /// + /// Inserts a new view's transaction status stream associated with a specific block hash into + /// the stream map. + fn add_stream(&mut self, block_hash: BlockHash, stream: TxStatusStream) { + self.status_stream_map.insert(block_hash, stream); + trace!(target: LOG_TARGET, "[{:?}] AddView view: {:?} views:{:?}", self.tx_hash, block_hash, self.status_stream_map.keys().collect::>()); + } + + /// Removes an existing transaction status stream. + /// + /// Removes a transaction status stream associated with a specific block hash from the + /// stream map. + fn remove_view(&mut self, block_hash: BlockHash) { + self.status_stream_map.remove(&block_hash); + trace!(target: LOG_TARGET, "[{:?}] RemoveView view: {:?} views:{:?}", self.tx_hash, block_hash, self.status_stream_map.keys().collect::>()); + } +} + +impl MultiViewListener +where + ChainApi: graph::ChainApi + 'static, + <::Block as BlockT>::Hash: Unpin, +{ + /// Creates new instance of `MultiViewListener`. + pub fn new() -> Self { + Self { controllers: Default::default() } + } + + /// Creates an external aggregated stream of events for given transaction. + /// + /// This method initializes an `ExternalWatcherContext` for the provided transaction hash, sets + /// up the necessary communication channels, and unfolds an external (meaning that it can be + /// exposed to [`sc_transaction_pool_api::TransactionPool`] API client e.g. rpc) stream of + /// transaction status events. If an external watcher is already present for the given + /// transaction, it returns `None`. + pub(crate) fn create_external_watcher_for_tx( + &self, + tx_hash: ExtrinsicHash, + ) -> Option> { + let mut controllers = self.controllers.write(); + if controllers.contains_key(&tx_hash) { + return None + } + + trace!(target: LOG_TARGET, "[{:?}] create_external_watcher_for_tx", tx_hash); + + let (tx, rx) = mpsc::tracing_unbounded("txpool-multi-view-listener", 32); + controllers.insert(tx_hash, tx); + + let ctx = ExternalWatcherContext::new(tx_hash, rx); + + Some( + futures::stream::unfold(ctx, |mut ctx| async move { + if ctx.terminate { + return None + } + loop { + tokio::select! { + biased; + Some((view_hash, status)) = next_event(&mut ctx.status_stream_map) => { + if let Some(new_status) = ctx.handle(status, view_hash) { + log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: {new_status:?}", ctx.tx_hash); + return Some((new_status, ctx)) + } + }, + cmd = ctx.command_receiver.next() => { + log::trace!(target: LOG_TARGET, "[{:?}] select::rx views:{:?}", + ctx.tx_hash, + ctx.status_stream_map.keys().collect::>() + ); + match cmd? { + ControllerCommand::AddViewStream(h,stream) => { + ctx.add_stream(h, stream); + }, + ControllerCommand::RemoveViewStream(h) => { + ctx.remove_view(h); + }, + ControllerCommand::TransactionInvalidated => { + if ctx.handle_invalidate_transaction() { + log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Invalid", ctx.tx_hash); + return Some((TransactionStatus::Invalid, ctx)) + } + }, + ControllerCommand::FinalizeTransaction(block, index) => { + log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Finalized", ctx.tx_hash); + ctx.terminate = true; + return Some((TransactionStatus::Finalized((block, index)), ctx)) + }, + ControllerCommand::TransactionBroadcasted(peers) => { + log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Broadcasted", ctx.tx_hash); + return Some((TransactionStatus::Broadcast(peers), ctx)) + }, + ControllerCommand::TransactionDropped => { + log::trace!(target: LOG_TARGET, "[{:?}] mvl sending out: Dropped", ctx.tx_hash); + ctx.terminate = true; + return Some((TransactionStatus::Dropped, ctx)) + }, + } + }, + }; + } + }) + .boxed(), + ) + } + + /// Adds a view's transaction status stream for particular transaction. + /// + /// This method sends a `AddViewStream` command to the controller of each transaction to + /// remove the view's stream corresponding to the given block hash. + pub(crate) fn add_view_watcher_for_tx( + &self, + tx_hash: ExtrinsicHash, + block_hash: BlockHash, + stream: TxStatusStream, + ) { + let mut controllers = self.controllers.write(); + + if let Entry::Occupied(mut tx) = controllers.entry(tx_hash) { + if let Err(e) = tx + .get_mut() + .unbounded_send(ControllerCommand::AddViewStream(block_hash, stream)) + { + trace!(target: LOG_TARGET, "[{:?}] add_view_watcher_for_tx: send message failed: {:?}", tx_hash, e); + tx.remove(); + } + } + } + + /// Removes a view's stream associated with a specific view hash across all transactions. + /// + /// This method sends a `RemoveViewStream` command to the controller of each transaction to + /// remove the view's stream corresponding to the given block hash. + pub(crate) fn remove_view(&self, block_hash: BlockHash) { + self.controllers.write().retain(|tx_hash, sender| { + sender + .unbounded_send(ControllerCommand::RemoveViewStream(block_hash)) + .map_err(|e| { + log::trace!(target: LOG_TARGET, "[{:?}] remove_view: send message failed: {:?}", tx_hash, e); + e + }) + .is_ok() + }); + } + + /// Invalidate given transaction. + /// + /// This method sends a `TransactionInvalidated` command to the controller of each transaction + /// provided to process the invalidation request. + /// + /// The external event will be sent if no view is referencing the transaction as `Ready` or + /// `Future`. + pub(crate) fn invalidate_transactions(&self, invalid_hashes: &[ExtrinsicHash]) { + let mut controllers = self.controllers.write(); + invalid_hashes.iter().for_each(|tx_hash| { + if let Entry::Occupied(mut tx) = controllers.entry(*tx_hash) { + trace!(target: LOG_TARGET, "[{:?}] invalidate_transaction", tx_hash); + if let Err(e) = + tx.get_mut().unbounded_send(ControllerCommand::TransactionInvalidated) + { + trace!(target: LOG_TARGET, "[{:?}] invalidate_transaction: send message failed: {:?}", tx_hash, e); + tx.remove(); + } + } + }); + } + + /// Send `Broadcasted` event to listeners of all transactions. + /// + /// This method sends a `TransactionBroadcasted` command to the controller of each transaction + /// provided prompting the external `Broadcasted` event. + pub(crate) fn transactions_broadcasted( + &self, + propagated: HashMap, Vec>, + ) { + let mut controllers = self.controllers.write(); + propagated.into_iter().for_each(|(tx_hash, peers)| { + if let Entry::Occupied(mut tx) = controllers.entry(tx_hash) { + trace!(target: LOG_TARGET, "[{:?}] transaction_broadcasted", tx_hash); + if let Err(e) = tx.get_mut().unbounded_send(ControllerCommand::TransactionBroadcasted(peers)) { + trace!(target: LOG_TARGET, "[{:?}] transactions_broadcasted: send message failed: {:?}", tx_hash, e); + tx.remove(); + } + } + }); + } + + /// Send `Dropped` event to listeners of transactions. + /// + /// 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]) { + 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); + }; + } + } + } + + /// Send `Finalized` event for given transaction at given block. + /// + /// This will send `Finalized` event to the external watcher. + pub(crate) fn finalize_transaction( + &self, + tx_hash: ExtrinsicHash, + block: BlockHash, + idx: TxIndex, + ) { + let mut controllers = self.controllers.write(); + if let Some(tx) = controllers.remove(&tx_hash) { + trace!(target: LOG_TARGET, "[{:?}] finalize_transaction", tx_hash); + if let Err(e) = tx.unbounded_send(ControllerCommand::FinalizeTransaction(block, idx)) { + trace!(target: LOG_TARGET, "[{:?}] finalize_transaction: send message failed: {:?}", tx_hash, e); + } + }; + } + + /// Removes stale controllers. + pub(crate) fn remove_stale_controllers(&self) { + self.controllers.write().retain(|_, c| !c.is_closed()); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::tests::TestApi; + use futures::{stream, StreamExt}; + use sp_core::H256; + + type MultiViewListener = super::MultiViewListener; + + #[tokio::test] + async fn test01() { + sp_tracing::try_init_simple(); + let listener = MultiViewListener::new(); + + let block_hash = H256::repeat_byte(0x01); + let events = vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash, 0)), + TransactionStatus::Finalized((block_hash, 0)), + ]; + + let tx_hash = H256::repeat_byte(0x0a); + let external_watcher = listener.create_external_watcher_for_tx(tx_hash).unwrap(); + let handle = tokio::spawn(async move { external_watcher.collect::>().await }); + + let view_stream = futures::stream::iter(events.clone()); + + listener.add_view_watcher_for_tx(tx_hash, block_hash, view_stream.boxed()); + + let out = handle.await.unwrap(); + assert_eq!(out, events); + log::debug!("out: {:#?}", out); + } + + #[tokio::test] + async fn test02() { + sp_tracing::try_init_simple(); + let listener = MultiViewListener::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let events0 = vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash0, 0)), + ]; + + let block_hash1 = H256::repeat_byte(0x02); + let events1 = vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash1, 0)), + TransactionStatus::Finalized((block_hash1, 0)), + ]; + + let tx_hash = H256::repeat_byte(0x0a); + let external_watcher = listener.create_external_watcher_for_tx(tx_hash).unwrap(); + + let view_stream0 = futures::stream::iter(events0.clone()); + let view_stream1 = futures::stream::iter(events1.clone()); + + let handle = tokio::spawn(async move { external_watcher.collect::>().await }); + + listener.add_view_watcher_for_tx(tx_hash, block_hash0, view_stream0.boxed()); + listener.add_view_watcher_for_tx(tx_hash, block_hash1, view_stream1.boxed()); + + let out = handle.await.unwrap(); + + log::debug!("out: {:#?}", out); + assert!(out.iter().all(|v| vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash0, 0)), + TransactionStatus::InBlock((block_hash1, 0)), + TransactionStatus::Finalized((block_hash1, 0)), + ] + .contains(v))); + assert_eq!(out.len(), 5); + } + + #[tokio::test] + async fn test03() { + sp_tracing::try_init_simple(); + let listener = MultiViewListener::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let events0 = vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash0, 0)), + ]; + + let block_hash1 = H256::repeat_byte(0x02); + let events1 = vec![TransactionStatus::Future]; + + let tx_hash = H256::repeat_byte(0x0a); + let external_watcher = listener.create_external_watcher_for_tx(tx_hash).unwrap(); + let handle = tokio::spawn(async move { external_watcher.collect::>().await }); + + let view_stream0 = futures::stream::iter(events0.clone()); + let view_stream1 = futures::stream::iter(events1.clone()); + + listener.add_view_watcher_for_tx(tx_hash, block_hash0, view_stream0.boxed()); + listener.add_view_watcher_for_tx(tx_hash, block_hash1, view_stream1.boxed()); + + listener.invalidate_transactions(&[tx_hash]); + + let out = handle.await.unwrap(); + log::debug!("out: {:#?}", out); + assert!(out.iter().all(|v| vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash0, 0)), + TransactionStatus::Invalid + ] + .contains(v))); + assert_eq!(out.len(), 4); + } + + #[tokio::test] + async fn test032() { + sp_tracing::try_init_simple(); + let listener = MultiViewListener::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let events0_tx0 = vec![TransactionStatus::Future]; + let events0_tx1 = vec![TransactionStatus::Ready]; + + let block_hash1 = H256::repeat_byte(0x02); + let events1_tx0 = + vec![TransactionStatus::Ready, TransactionStatus::InBlock((block_hash1, 0))]; + let events1_tx1 = vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash1, 1)), + TransactionStatus::Finalized((block_hash1, 1)), + ]; + + let tx0_hash = H256::repeat_byte(0x0a); + let tx1_hash = H256::repeat_byte(0x0b); + let external_watcher_tx0 = listener.create_external_watcher_for_tx(tx0_hash).unwrap(); + let external_watcher_tx1 = listener.create_external_watcher_for_tx(tx1_hash).unwrap(); + + let handle0 = tokio::spawn(async move { external_watcher_tx0.collect::>().await }); + let handle1 = tokio::spawn(async move { external_watcher_tx1.collect::>().await }); + + let view0_tx0_stream = futures::stream::iter(events0_tx0.clone()); + let view0_tx1_stream = futures::stream::iter(events0_tx1.clone()); + + let view1_tx0_stream = futures::stream::iter(events1_tx0.clone()); + let view1_tx1_stream = futures::stream::iter(events1_tx1.clone()); + + listener.add_view_watcher_for_tx(tx0_hash, block_hash0, view0_tx0_stream.boxed()); + listener.add_view_watcher_for_tx(tx0_hash, block_hash1, view1_tx0_stream.boxed()); + listener.add_view_watcher_for_tx(tx1_hash, block_hash0, view0_tx1_stream.boxed()); + listener.add_view_watcher_for_tx(tx1_hash, block_hash1, view1_tx1_stream.boxed()); + + listener.invalidate_transactions(&[tx0_hash]); + listener.invalidate_transactions(&[tx1_hash]); + + let out_tx0 = handle0.await.unwrap(); + let out_tx1 = handle1.await.unwrap(); + + log::debug!("out_tx0: {:#?}", out_tx0); + log::debug!("out_tx1: {:#?}", out_tx1); + assert!(out_tx0.iter().all(|v| vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash1, 0)), + TransactionStatus::Invalid + ] + .contains(v))); + + assert!(out_tx1.iter().all(|v| vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash1, 1)), + TransactionStatus::Finalized((block_hash1, 1)) + ] + .contains(v))); + assert_eq!(out_tx0.len(), 4); + assert_eq!(out_tx1.len(), 3); + } + + #[tokio::test] + async fn test04() { + sp_tracing::try_init_simple(); + let listener = MultiViewListener::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let events0 = vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash0, 0)), + ]; + + let block_hash1 = H256::repeat_byte(0x02); + let events1 = vec![TransactionStatus::Future]; + + let tx_hash = H256::repeat_byte(0x0a); + let external_watcher = listener.create_external_watcher_for_tx(tx_hash).unwrap(); + + //views will keep transaction valid, invalidation shall not happen + let view_stream0 = futures::stream::iter(events0.clone()).chain(stream::pending().boxed()); + let view_stream1 = futures::stream::iter(events1.clone()).chain(stream::pending().boxed()); + + let handle = tokio::spawn(async move { + // views are still there, we need to fetch 3 events + external_watcher.take(3).collect::>().await + }); + + listener.add_view_watcher_for_tx(tx_hash, block_hash0, view_stream0.boxed()); + listener.add_view_watcher_for_tx(tx_hash, block_hash1, view_stream1.boxed()); + + listener.invalidate_transactions(&[tx_hash]); + + let out = handle.await.unwrap(); + log::debug!("out: {:#?}", out); + + // invalid shall not be sent + assert!(out.iter().all(|v| vec![ + TransactionStatus::Future, + TransactionStatus::Ready, + TransactionStatus::InBlock((block_hash0, 0)), + ] + .contains(v))); + assert_eq!(out.len(), 3); + } + + #[tokio::test] + async fn test05() { + sp_tracing::try_init_simple(); + let listener = MultiViewListener::new(); + + let block_hash0 = H256::repeat_byte(0x01); + let events0 = vec![TransactionStatus::Invalid]; + + let tx_hash = H256::repeat_byte(0x0a); + let external_watcher = listener.create_external_watcher_for_tx(tx_hash).unwrap(); + let handle = tokio::spawn(async move { external_watcher.collect::>().await }); + + let view_stream0 = futures::stream::iter(events0.clone()).chain(stream::pending().boxed()); + + // Note: this generates actual Invalid event. + // Invalid event from View's stream is intentionally ignored. + listener.invalidate_transactions(&[tx_hash]); + + listener.add_view_watcher_for_tx(tx_hash, block_hash0, view_stream0.boxed()); + + let out = handle.await.unwrap(); + log::debug!("out: {:#?}", out); + + assert!(out.iter().all(|v| vec![TransactionStatus::Invalid].contains(v))); + assert_eq!(out.len(), 1); + } +} 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 new file mode 100644 index 000000000000..9464ab3f5766 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/revalidation_worker.rs @@ -0,0 +1,240 @@ +// 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 . + +//! The background worker for the [`View`] and [`TxMemPool`] revalidation. +//! +//! The [*Background tasks*](../index.html#background-tasks) section provides some extra details on +//! revalidation process. + +use std::{marker::PhantomData, pin::Pin, sync::Arc}; + +use crate::{graph::ChainApi, LOG_TARGET}; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; +use sp_blockchain::HashAndNumber; +use sp_runtime::traits::Block as BlockT; + +use super::tx_mem_pool::TxMemPool; +use futures::prelude::*; + +use super::view::{FinishRevalidationWorkerChannels, View}; + +/// Revalidation request payload sent from the queue to the worker. +enum WorkerPayload +where + Block: BlockT, + Api: ChainApi + 'static, +{ + /// Request to revalidated the given instance of the [`View`] + /// + /// Communication channels with maintain thread are also provided. + RevalidateView(Arc>, FinishRevalidationWorkerChannels), + /// Request to revalidated the given instance of the [`TxMemPool`] at provided block hash. + RevalidateMempool(Arc>, HashAndNumber), +} + +/// The background revalidation worker. +struct RevalidationWorker { + _phantom: PhantomData, +} + +impl RevalidationWorker +where + Block: BlockT, + ::Hash: Unpin, +{ + /// Create a new instance of the background worker. + fn new() -> Self { + Self { _phantom: Default::default() } + } + + /// A background worker main loop. + /// + /// Waits for and dispatches the [`WorkerPayload`] messages sent from the + /// [`RevalidationQueue`]. + pub async fn run + 'static>( + self, + from_queue: TracingUnboundedReceiver>, + ) { + let mut from_queue = from_queue.fuse(); + + loop { + let Some(payload) = from_queue.next().await else { + // R.I.P. worker! + break; + }; + match payload { + WorkerPayload::RevalidateView(view, worker_channels) => + view.revalidate(worker_channels).await, + WorkerPayload::RevalidateMempool(mempool, finalized_hash_and_number) => + mempool.revalidate(finalized_hash_and_number).await, + }; + } + } +} + +/// A Revalidation queue. +/// +/// Allows to send the revalidation requests to the [`RevalidationWorker`]. +pub struct RevalidationQueue +where + Api: ChainApi + 'static, + Block: BlockT, +{ + background: Option>>, +} + +impl RevalidationQueue +where + Api: ChainApi + 'static, + Block: BlockT, + ::Hash: Unpin, +{ + /// New revalidation queue without background worker. + /// + /// All validation requests will be blocking. + pub fn new() -> Self { + Self { background: None } + } + + /// New revalidation queue with background worker. + /// + /// All validation requests will be executed in the background. + pub fn new_with_worker() -> (Self, Pin + Send>>) { + let (to_worker, from_queue) = tracing_unbounded("mpsc_revalidation_queue", 100_000); + (Self { background: Some(to_worker) }, RevalidationWorker::new().run(from_queue).boxed()) + } + + /// Queue the view for later revalidation. + /// + /// If the queue is configured with background worker, this will return immediately. + /// If the queue is configured without background worker, this will resolve after + /// revalidation is actually done. + /// + /// Schedules execution of the [`View::revalidate`]. + pub async fn revalidate_view( + &self, + view: Arc>, + finish_revalidation_worker_channels: FinishRevalidationWorkerChannels, + ) { + log::trace!( + target: LOG_TARGET, + "revalidation_queue::revalidate_view: Sending view to revalidation queue at {}", + view.at.hash + ); + + if let Some(ref to_worker) = self.background { + if let Err(e) = to_worker.unbounded_send(WorkerPayload::RevalidateView( + view, + finish_revalidation_worker_channels, + )) { + log::warn!(target: LOG_TARGET, "revalidation_queue::revalidate_view: Failed to update background worker: {:?}", e); + } + } else { + view.revalidate(finish_revalidation_worker_channels).await + } + } + + /// Revalidates the given mempool instance. + /// + /// If queue configured with background worker, this will return immediately. + /// If queue configured without background worker, this will resolve after + /// revalidation is actually done. + /// + /// Schedules execution of the [`TxMemPool::revalidate`]. + pub async fn revalidate_mempool( + &self, + mempool: Arc>, + finalized_hash: HashAndNumber, + ) { + log::trace!( + target: LOG_TARGET, + "Sent mempool to revalidation queue at hash: {:?}", + finalized_hash + ); + + if let Some(ref to_worker) = self.background { + if let Err(e) = + to_worker.unbounded_send(WorkerPayload::RevalidateMempool(mempool, finalized_hash)) + { + log::warn!(target: LOG_TARGET, "Failed to update background worker: {:?}", e); + } + } else { + mempool.revalidate(finalized_hash).await + } + } +} + +#[cfg(test)] +//todo: add more tests [#5480] +mod tests { + use super::*; + use crate::{ + common::tests::{uxt, TestApi}, + fork_aware_txpool::view::FinishRevalidationLocalChannels, + }; + 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; + #[test] + fn revalidation_queue_works() { + let api = Arc::new(TestApi::default()); + let block0 = api.expect_hash_and_number(0); + + let view = Arc::new(View::new( + api.clone(), + block0, + Default::default(), + Default::default(), + false.into(), + )); + let queue = Arc::new(RevalidationQueue::new()); + + let uxt = uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }); + + let _ = block_on( + view.submit_many(TransactionSource::External, std::iter::once(uxt.clone().into())), + ); + assert_eq!(api.validation_requests().len(), 1); + + let (finish_revalidation_request_tx, finish_revalidation_request_rx) = + tokio::sync::mpsc::channel(1); + let (revalidation_result_tx, revalidation_result_rx) = tokio::sync::mpsc::channel(1); + + let finish_revalidation_worker_channels = FinishRevalidationWorkerChannels::new( + finish_revalidation_request_rx, + revalidation_result_tx, + ); + + let _finish_revalidation_local_channels = FinishRevalidationLocalChannels::new( + finish_revalidation_request_tx, + revalidation_result_rx, + ); + + block_on(queue.revalidate_view(view.clone(), finish_revalidation_worker_channels)); + + assert_eq!(api.validation_requests().len(), 2); + // number of ready + assert_eq!(view.status().ready, 1); + } +} 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 new file mode 100644 index 000000000000..86c07008c3f3 --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/tx_mem_pool.rs @@ -0,0 +1,596 @@ +// 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 . + +//! Transaction memory pool, container for watched and unwatched transactions. +//! Acts as a buffer which collect transactions before importing them to the views. Following are +//! the crucial use cases when it is needed: +//! - empty pool (no views yet) +//! - potential races between creation of view and submitting transaction (w/o intermediary buffer +//! some transactions could be lost) +//! - the transaction can be invalid on some forks (and thus the associated views may not contain +//! it), while on other forks tx can be valid. Depending on which view is chosen to be cloned, +//! such transaction could not be present in the newly created view. + +use super::{metrics::MetricsLink as PrometheusMetrics, multi_view_listener::MultiViewListener}; +use crate::{ + common::log_xt::log_xt_trace, + graph, + graph::{tracked_map::Size, ExtrinsicFor, ExtrinsicHash}, + LOG_TARGET, +}; +use futures::FutureExt; +use itertools::Itertools; +use sc_transaction_pool_api::TransactionSource; +use sp_blockchain::HashAndNumber; +use sp_runtime::{ + traits::Block as BlockT, + transaction_validity::{InvalidTransaction, TransactionValidityError}, +}; +use std::{ + collections::HashMap, + sync::{atomic, atomic::AtomicU64, Arc}, + time::Instant, +}; + +/// The minimum interval between single transaction revalidations. Given in blocks. +pub(crate) const TXMEMPOOL_REVALIDATION_PERIOD: u64 = 10; + +/// The number of transactions revalidated in single revalidation batch. +pub(crate) const TXMEMPOOL_MAX_REVALIDATION_BATCH_SIZE: usize = 1000; + +/// The maximum number of transactions kept in the mem pool. Given as multiple of +/// the view's total limit. +pub const TXMEMPOOL_TRANSACTION_LIMIT_MULTIPLIER: usize = 4; + +/// Represents the transaction in the intermediary buffer. +#[derive(Debug)] +pub(crate) struct TxInMemPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, +{ + //todo: add listener for updating listeners with events [#5495] + /// Is the progress of transaction watched. + /// + /// Was transaction sent with `submit_and_watch`. + watched: bool, + /// Extrinsic actual body. + tx: ExtrinsicFor, + /// Size of the extrinsics actual body. + bytes: usize, + /// Transaction source. + source: TransactionSource, + /// 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. + //If future transactions are stuck in tx_mem_pool (due to limits being hit), we need a means + // to replace them somehow with newly coming transactions. + // For sure priority is one of them, but some additional criteria maybe required. + // + // The other maybe simple solution for this could be just obeying 10% limit for future in + // tx_mem_pool. Oldest future transaction could be just dropped. *(Status at finalized would + // also be needed). Probably is_future_at_finalized:Option flag will be enought +} + +impl TxInMemPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, +{ + /// Shall the progress of transaction be watched. + /// + /// Was transaction sent with `submit_and_watch`. + fn is_watched(&self) -> bool { + self.watched + } + + /// Creates a new instance of wrapper for unwatched transaction. + fn new_unwatched(source: TransactionSource, tx: ExtrinsicFor, bytes: usize) -> Self { + Self { watched: false, tx, source, validated_at: AtomicU64::new(0), bytes } + } + + /// Creates a new instance of wrapper for watched transaction. + fn new_watched(source: TransactionSource, tx: ExtrinsicFor, bytes: usize) -> Self { + Self { watched: true, tx, source, validated_at: AtomicU64::new(0), bytes } + } + + /// Provides a clone of actual transaction body. + /// + /// Operation is cheap, as the body is `Arc`. + pub(crate) fn tx(&self) -> ExtrinsicFor { + self.tx.clone() + } + + /// Returns the source of the transaction. + pub(crate) fn source(&self) -> TransactionSource { + self.source + } +} + +impl Size for Arc> +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, +{ + fn size(&self) -> usize { + self.bytes + } +} + +type InternalTxMemPoolMap = + graph::tracked_map::TrackedMap, Arc>>; + +/// An intermediary transactions buffer. +/// +/// Keeps all the transaction which are potentially valid. Transactions that were finalized or +/// transactions that are invalid at finalized blocks are removed, either while handling the +/// `Finalized` event, or during revalidation process. +/// +/// All transactions from a`TxMemPool` are submitted to the newly created views. +/// +/// All newly submitted transactions goes into the `TxMemPool`. +pub(super) struct TxMemPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, +{ + /// A shared API instance necessary for blockchain related operations. + api: Arc, + + /// A shared instance of the `MultiViewListener`. + /// + /// Provides a side-channel allowing to send per-transaction state changes notification. + //todo: could be removed after removing watched field (and adding listener into tx) [#5495] + listener: Arc>, + + /// A map that stores the transactions currently in the memory pool. + /// + /// 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: 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, +} + +impl TxMemPool +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, + ::Hash: Unpin, +{ + /// Creates a new `TxMemPool` instance with the given API, listener, metrics, + /// and max transaction count. + pub(super) fn new( + api: Arc, + listener: Arc>, + metrics: PrometheusMetrics, + max_transactions_count: usize, + max_transactions_total_bytes: usize, + ) -> Self { + 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, + 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, + } + } + + /// Retrieves a transaction by its hash if it exists in the memory pool. + pub(super) fn get_by_hash( + &self, + hash: ExtrinsicHash, + ) -> Option> { + self.transactions.read().get(&hash).map(|t| t.tx()) + } + + /// Returns a tuple with the count of unwatched and watched transactions in the memory pool. + 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 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, + hash: ExtrinsicHash, + tx: TxInMemPool, + ) -> 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) => { + transactions.insert(hash, Arc::from(tx)); + Ok(hash) + }, + (_, 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); + + result + } + + /// Adds a new unwatched transactions to the internal buffer not exceeding the limit. + /// + /// Returns the vector of results for each transaction, the order corresponds to the input + /// vector. + pub(super) fn extend_unwatched( + &self, + source: TransactionSource, + xts: &[ExtrinsicFor], + ) -> Vec, ChainApi::Error>> { + let result = xts + .iter() + .map(|xt| { + let (hash, length) = self.api.hash_and_length(&xt); + self.try_insert(hash, TxInMemPool::new_unwatched(source, xt.clone(), length)) + }) + .collect::>(); + result + } + + /// Adds a new watched transaction to the memory pool if it does not exceed the maximum allowed + /// transaction count. + pub(super) fn push_watched( + &self, + source: TransactionSource, + xt: ExtrinsicFor, + ) -> Result, ChainApi::Error> { + let (hash, length) = self.api.hash_and_length(&xt); + self.try_insert(hash, TxInMemPool::new_watched(source, xt.clone(), length)) + } + + /// 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); + }); + + self.listener.transactions_dropped(to_be_removed); + } + + /// Clones and returns a `HashMap` of references to all unwatched transactions in the memory + /// pool. + pub(super) fn clone_unwatched( + &self, + ) -> HashMap, Arc>> { + self.transactions + .read() + .iter() + .filter_map(|(hash, tx)| (!tx.is_watched()).then(|| (*hash, tx.clone()))) + .collect::>() + } + + /// Clones and returns a `HashMap` of references to all watched transactions in the memory pool. + pub(super) fn clone_watched( + &self, + ) -> HashMap, Arc>> { + self.transactions + .read() + .iter() + .filter_map(|(hash, tx)| (tx.is_watched()).then(|| (*hash, tx.clone()))) + .collect::>() + } + + /// Removes a transaction from the memory pool based on a given hash. + pub(super) fn remove(&self, hash: ExtrinsicHash) { + let _ = self.transactions.write().remove(&hash); + } + + /// Revalidates a batch of transactions against the provided finalized block. + /// + /// Returns a vector of invalid transaction hashes. + async fn revalidate_inner(&self, finalized_block: HashAndNumber) -> Vec { + log::trace!(target: LOG_TARGET, "mempool::revalidate at:{finalized_block:?}"); + let start = Instant::now(); + + let (count, input) = { + let transactions = self.transactions.clone_map(); + + ( + transactions.len(), + transactions + .into_iter() + .filter(|xt| { + let finalized_block_number = finalized_block.number.into().as_u64(); + xt.1.validated_at.load(atomic::Ordering::Relaxed) + + TXMEMPOOL_REVALIDATION_PERIOD < + finalized_block_number + }) + .sorted_by_key(|tx| tx.1.validated_at.load(atomic::Ordering::Relaxed)) + .take(TXMEMPOOL_MAX_REVALIDATION_BATCH_SIZE), + ) + }; + + 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| { + 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(); + + let duration = start.elapsed(); + + let invalid_hashes = validation_results + .into_iter() + .filter_map(|(xt_hash, validation_result)| match validation_result { + Ok(Ok(_)) | + Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Future))) => None, + Err(_) | + Ok(Err(TransactionValidityError::Unknown(_))) | + Ok(Err(TransactionValidityError::Invalid(_))) => { + log::trace!( + target: LOG_TARGET, + "[{:?}]: Purging: invalid: {:?}", + xt_hash, + validation_result, + ); + Some(xt_hash) + }, + }) + .collect::>(); + + log::debug!( + target: LOG_TARGET, + "mempool::revalidate: at {finalized_block:?} count:{input_len}/{count} purged:{} took {duration:?}", invalid_hashes.len(), + ); + + invalid_hashes + } + + /// Removes the finalized transactions from the memory pool, using a provided list of hashes. + pub(super) async fn purge_finalized_transactions( + &self, + finalized_xts: &Vec>, + ) { + log::debug!(target: LOG_TARGET, "purge_finalized_transactions count:{:?}", finalized_xts.len()); + log_xt_trace!(target: LOG_TARGET, finalized_xts, "[{:?}] purged finalized transactions"); + let mut transactions = self.transactions.write(); + finalized_xts.iter().for_each(|t| { + transactions.remove(t); + }); + } + + /// Revalidates transactions in the memory pool against a given finalized block and removes + /// invalid ones. + pub(super) async fn revalidate(&self, finalized_block: HashAndNumber) { + log::trace!(target: LOG_TARGET, "purge_transactions at:{:?}", finalized_block); + let invalid_hashes = self.revalidate_inner(finalized_block.clone()).await; + + self.metrics.report(|metrics| { + metrics.mempool_revalidation_invalid_txs.inc_by(invalid_hashes.len() as _) + }); + + let mut transactions = self.transactions.write(); + invalid_hashes.iter().for_each(|i| { + transactions.remove(i); + }); + self.listener.invalidate_transactions(&invalid_hashes); + } +} + +#[cfg(test)] +mod tx_mem_pool_tests { + use super::*; + use crate::{common::tests::TestApi, graph::ChainApi}; + use substrate_test_runtime::{AccountId, Extrinsic, ExtrinsicBuilder, Transfer, H256}; + use substrate_test_runtime_client::AccountKeyring::*; + fn uxt(nonce: u64) -> Extrinsic { + crate::common::tests::uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce, + }) + } + + #[test] + fn extend_unwatched_obeys_limit() { + let max = 10; + let api = Arc::from(TestApi::default()); + let mempool = TxMemPool::new_test(api, max, usize::MAX); + + let xts = (0..max + 1).map(|x| Arc::from(uxt(x as _))).collect::>(); + + let results = mempool.extend_unwatched(TransactionSource::External, &xts); + assert!(results.iter().take(max).all(Result::is_ok)); + assert!(matches!( + results.into_iter().last().unwrap().unwrap_err(), + sc_transaction_pool_api::error::Error::ImmediatelyDropped + )); + } + + #[test] + fn extend_unwatched_detects_already_imported() { + sp_tracing::try_init_simple(); + let max = 10; + let api = Arc::from(TestApi::default()); + 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()); + + let results = mempool.extend_unwatched(TransactionSource::External, &xts); + assert!(results.iter().take(max - 1).all(Result::is_ok)); + assert!(matches!( + results.into_iter().last().unwrap().unwrap_err(), + sc_transaction_pool_api::error::Error::AlreadyImported(_) + )); + } + + #[test] + fn push_obeys_limit() { + let max = 10; + let api = Arc::from(TestApi::default()); + let mempool = TxMemPool::new_test(api, max, usize::MAX); + + let xts = (0..max).map(|x| Arc::from(uxt(x as _))).collect::>(); + + let results = mempool.extend_unwatched(TransactionSource::External, &xts); + assert!(results.iter().all(Result::is_ok)); + + let xt = Arc::from(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(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 + )); + } + + #[test] + fn push_detects_already_imported() { + let max = 10; + let api = Arc::from(TestApi::default()); + 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(); + let xt1 = xts.iter().next().unwrap().clone(); + + let results = mempool.extend_unwatched(TransactionSource::External, &xts); + assert!(results.iter().all(Result::is_ok)); + + let result = mempool.push_watched(TransactionSource::External, xt0); + assert!(matches!( + result.unwrap_err(), + sc_transaction_pool_api::error::Error::AlreadyImported(_) + )); + let mut result = mempool.extend_unwatched(TransactionSource::External, &[xt1]); + assert!(matches!( + result.pop().unwrap().unwrap_err(), + sc_transaction_pool_api::error::Error::AlreadyImported(_) + )); + } + + #[test] + fn count_works() { + let max = 100; + let api = Arc::from(TestApi::default()); + let mempool = TxMemPool::new_test(api, max, usize::MAX); + + let xts0 = (0..10).map(|x| Arc::from(uxt(x as _))).collect::>(); + + let results = mempool.extend_unwatched(TransactionSource::External, &xts0); + assert!(results.iter().all(Result::is_ok)); + + let xts1 = (0..5).map(|x| Arc::from(uxt(2 * x))).collect::>(); + let results = xts1 + .into_iter() + .map(|t| mempool.push_watched(TransactionSource::External, t)) + .collect::>(); + 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 new file mode 100644 index 000000000000..99095d88cb0a --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/view.rs @@ -0,0 +1,458 @@ +// 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 . + +//! Transaction pool view. +//! +//! The View represents the state of the transaction pool at given block. The view is created when +//! new block is notified to transaction pool. Views are removed on finalization. +//! +//! Refer to [*View*](../index.html#view) section for more details. + +use super::metrics::MetricsLink as PrometheusMetrics; +use crate::{ + common::log_xt::log_xt_trace, + graph::{ + self, 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 sp_blockchain::HashAndNumber; +use sp_runtime::{ + generic::BlockId, traits::Block as BlockT, transaction_validity::TransactionValidityError, + SaturatedConversion, +}; +use std::{collections::HashMap, sync::Arc, time::Instant}; + +pub(super) struct RevalidationResult { + revalidated: HashMap, ValidatedTransactionFor>, + invalid_hashes: Vec>, +} + +/// Used to obtain result from RevalidationWorker on View side. +pub(super) type RevalidationResultReceiver = + tokio::sync::mpsc::Receiver>; + +/// Used to send revalidation result from RevalidationWorker to View. +pub(super) type RevalidationResultSender = + tokio::sync::mpsc::Sender>; + +/// Used to receive finish-revalidation-request from View on RevalidationWorker side. +pub(super) type FinishRevalidationRequestReceiver = tokio::sync::mpsc::Receiver<()>; + +/// Used to send finish-revalidation-request from View to RevalidationWorker. +pub(super) type FinishRevalidationRequestSender = tokio::sync::mpsc::Sender<()>; + +/// Endpoints of channels used on View side (maintain thread) +pub(super) struct FinishRevalidationLocalChannels { + /// Used to send finish revalidation request. + finish_revalidation_request_tx: Option, + /// Used to receive revalidation results. + revalidation_result_rx: RevalidationResultReceiver, +} + +impl FinishRevalidationLocalChannels { + /// Creates a new instance of endpoints for channels used on View side + pub fn new( + finish_revalidation_request_tx: FinishRevalidationRequestSender, + revalidation_result_rx: RevalidationResultReceiver, + ) -> Self { + Self { + finish_revalidation_request_tx: Some(finish_revalidation_request_tx), + revalidation_result_rx, + } + } + + /// Removes a finish revalidation sender + /// + /// Should be called when revalidation was already terminated and finish revalidation message is + /// no longer expected. + fn remove_sender(&mut self) { + self.finish_revalidation_request_tx = None; + } +} + +/// Endpoints of channels used on `RevalidationWorker` side (background thread) +pub(super) struct FinishRevalidationWorkerChannels { + /// Used to receive finish revalidation request. + finish_revalidation_request_rx: FinishRevalidationRequestReceiver, + /// Used to send revalidation results. + revalidation_result_tx: RevalidationResultSender, +} + +impl FinishRevalidationWorkerChannels { + /// Creates a new instance of endpoints for channels used on `RevalidationWorker` side + pub fn new( + finish_revalidation_request_rx: FinishRevalidationRequestReceiver, + revalidation_result_tx: RevalidationResultSender, + ) -> Self { + Self { finish_revalidation_request_rx, revalidation_result_tx } + } +} + +/// Represents the state of transaction pool for given block. +/// +/// Refer to [*View*](../index.html#view) section for more details on the purpose and life cycle of +/// the `View`. +pub(super) struct View { + /// The internal pool keeping the set of ready and future transaction at the given block. + pub(super) pool: graph::Pool, + /// The hash and number of the block with which this view is associated. + pub(super) at: HashAndNumber, + /// Endpoints of communication channel with background worker. + revalidation_worker_channels: Mutex>>, + /// Prometheus's metrics endpoint. + metrics: PrometheusMetrics, +} + +impl View +where + ChainApi: graph::ChainApi, + ::Hash: Unpin, +{ + /// Creates a new empty view. + pub(super) fn new( + api: Arc, + at: HashAndNumber, + options: graph::Options, + metrics: PrometheusMetrics, + is_validator: IsValidator, + ) -> Self { + metrics.report(|metrics| metrics.non_cloned_views.inc()); + Self { + pool: graph::Pool::new(options, is_validator, api), + at, + revalidation_worker_channels: Mutex::from(None), + metrics, + } + } + + /// Creates a copy of the other view. + pub(super) fn new_from_other(&self, at: &HashAndNumber) -> Self { + View { + at: at.clone(), + pool: self.pool.deep_clone(), + revalidation_worker_channels: Mutex::from(None), + metrics: self.metrics.clone(), + } + } + + /// Imports many unvalidated extrinsics into the view. + pub(super) async fn submit_many( + &self, + source: TransactionSource, + 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 + } else { + self.pool.submit_at(&self.at, source, 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, + 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); + self.pool.submit_and_watch(&self.at, source, xt).await + } + + /// Synchronously imports single unvalidated extrinsics into the view. + pub(super) fn submit_local( + &self, + xt: ExtrinsicFor, + ) -> Result, ChainApi::Error> { + let (hash, length) = self.pool.validated_pool().api().hash_and_length(&xt); + log::trace!(target: LOG_TARGET, "[{:?}] view::submit_local at:{}", hash, self.at.hash); + + let validity = self + .pool + .validated_pool() + .api() + .validate_transaction_blocking( + self.at.hash, + TransactionSource::Local, + Arc::from(xt.clone()), + )? + .map_err(|e| { + match e { + TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i), + TransactionValidityError::Unknown(u) => TxPoolError::UnknownTransaction(u), + } + .into() + })?; + + let block_number = self + .pool + .validated_pool() + .api() + .block_id_to_number(&BlockId::hash(self.at.hash))? + .ok_or_else(|| TxPoolError::InvalidBlockId(format!("{:?}", self.at.hash)))?; + + let validated = ValidatedTransaction::valid_at( + block_number.saturated_into::(), + hash, + TransactionSource::Local, + Arc::from(xt), + length, + validity, + ); + + self.pool.validated_pool().submit(vec![validated]).remove(0) + } + + /// Status of the pool associated with the view. + pub(super) fn status(&self) -> PoolStatus { + self.pool.validated_pool().status() + } + + /// Creates a watcher for given transaction. + /// + /// Intended to be called for the transaction that already exists in the pool + pub(super) fn create_watcher( + &self, + tx_hash: ExtrinsicHash, + ) -> Watcher, ExtrinsicHash> { + //todo(minor): some assert could be added here - to make sure that transaction actually + // exists in the view. + self.pool.validated_pool().create_watcher(tx_hash) + } + + /// Revalidates some part of transaction from the internal pool. + /// + /// Intended to be called from the revalidation worker. The revalidation process can be + /// terminated by sending a message to the `rx` channel provided within + /// `finish_revalidation_worker_channels`. Revalidation results are sent back over the `tx` + /// channels and shall be applied in maintain thread. + /// + /// View revalidation currently is not throttled, and until not terminated it will revalidate + /// all the transactions. Note: this can be improved if CPU usage due to revalidation becomes a + /// problem. + pub(super) async fn revalidate( + &self, + finish_revalidation_worker_channels: FinishRevalidationWorkerChannels, + ) { + let FinishRevalidationWorkerChannels { + mut finish_revalidation_request_rx, + revalidation_result_tx, + } = finish_revalidation_worker_channels; + + log::trace!(target:LOG_TARGET, "view::revalidate: at {} starting", self.at.hash); + let start = Instant::now(); + let validated_pool = self.pool.validated_pool(); + let api = validated_pool.api(); + + let batch: Vec<_> = validated_pool.ready().collect(); + let batch_len = batch.len(); + + //todo: sort batch by revalidation timestamp | maybe not needed at all? xts will be getting + //out of the view... + //todo: revalidate future, remove if invalid [#5496] + + let mut invalid_hashes = Vec::new(); + let mut revalidated = HashMap::new(); + + let mut validation_results = vec![]; + let mut batch_iter = batch.into_iter(); + loop { + let mut should_break = false; + tokio::select! { + _ = finish_revalidation_request_rx.recv() => { + log::trace!(target: LOG_TARGET, "view::revalidate: finish revalidation request received at {}.", self.at.hash); + break + } + _ = 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); + validation_results.push(validation_result); + } else { + self.revalidation_worker_channels.lock().as_mut().map(|ch| ch.remove_sender()); + should_break = true; + } + } => {} + } + + if should_break { + break; + } + } + + let revalidation_duration = start.elapsed(); + self.metrics.report(|metrics| { + metrics.view_revalidation_duration.observe(revalidation_duration.as_secs_f64()); + }); + log::debug!( + target:LOG_TARGET, + "view::revalidate: at {:?} count: {}/{} took {:?}", + self.at.hash, + validation_results.len(), + batch_len, + revalidation_duration + ); + log_xt_trace!(data:tuple, target:LOG_TARGET, validation_results.iter().map(|x| (x.1, &x.0)), "[{:?}] view::revalidateresult: {:?}"); + + for (validation_result, tx_hash, tx) in validation_results { + match validation_result { + Ok(Err(TransactionValidityError::Invalid(_))) => { + invalid_hashes.push(tx_hash); + }, + Ok(Ok(validity)) => { + revalidated.insert( + tx_hash, + ValidatedTransaction::valid_at( + self.at.number.saturated_into::(), + tx_hash, + tx.source, + tx.data.clone(), + api.hash_and_length(&tx.data).1, + validity, + ), + ); + }, + Ok(Err(TransactionValidityError::Unknown(e))) => { + log::trace!( + target: LOG_TARGET, + "[{:?}]: Removing. Cannot determine transaction validity: {:?}", + tx_hash, + e + ); + invalid_hashes.push(tx_hash); + }, + Err(validation_err) => { + log::trace!( + target: LOG_TARGET, + "[{:?}]: Removing due to error during revalidation: {}", + tx_hash, + validation_err + ); + invalid_hashes.push(tx_hash); + }, + } + } + + log::trace!(target:LOG_TARGET, "view::revalidate: sending revalidation result at {}", self.at.hash); + if let Err(e) = revalidation_result_tx + .send(RevalidationResult { invalid_hashes, revalidated }) + .await + { + log::trace!(target:LOG_TARGET, "view::revalidate: sending revalidation_result at {} failed {:?}", self.at.hash, e); + } + } + + /// Sends revalidation request to the background worker. + /// + /// Creates communication channels required to stop revalidation request and receive the + /// revalidation results and sends the revalidation request to the background worker. + /// + /// Intended to be called from maintain thread, at the very end of the maintain process. + /// + /// Refer to [*View revalidation*](../index.html#view-revalidation) for more details. + pub(super) async fn start_background_revalidation( + view: Arc, + revalidation_queue: Arc< + super::revalidation_worker::RevalidationQueue, + >, + ) { + log::trace!(target:LOG_TARGET,"view::start_background_revalidation: at {}", view.at.hash); + let (finish_revalidation_request_tx, finish_revalidation_request_rx) = + tokio::sync::mpsc::channel(1); + let (revalidation_result_tx, revalidation_result_rx) = tokio::sync::mpsc::channel(1); + + let finish_revalidation_worker_channels = FinishRevalidationWorkerChannels::new( + finish_revalidation_request_rx, + revalidation_result_tx, + ); + + let finish_revalidation_local_channels = FinishRevalidationLocalChannels::new( + finish_revalidation_request_tx, + revalidation_result_rx, + ); + + *view.revalidation_worker_channels.lock() = Some(finish_revalidation_local_channels); + revalidation_queue + .revalidate_view(view.clone(), finish_revalidation_worker_channels) + .await; + } + + /// Terminates a background view revalidation. + /// + /// Receives the results from the background worker and applies them to the internal pool. + /// Intended to be called from the maintain thread, at the very beginning of the maintain + /// process, before the new view is cloned and updated. Applying results before cloning ensures + /// that view contains up-to-date set of revalidated transactions. + /// + /// Refer to [*View revalidation*](../index.html#view-revalidation) for more details. + pub(super) async fn finish_revalidation(&self) { + log::trace!(target:LOG_TARGET,"view::finish_revalidation: at {}", self.at.hash); + let Some(revalidation_worker_channels) = self.revalidation_worker_channels.lock().take() + else { + log::trace!(target:LOG_TARGET, "view::finish_revalidation: no finish_revalidation_request_tx"); + return + }; + + let FinishRevalidationLocalChannels { + finish_revalidation_request_tx, + mut revalidation_result_rx, + } = revalidation_worker_channels; + + if let Some(finish_revalidation_request_tx) = finish_revalidation_request_tx { + if let Err(e) = finish_revalidation_request_tx.send(()).await { + log::trace!(target:LOG_TARGET, "view::finish_revalidation: sending cancellation request at {} failed {:?}", self.at.hash, e); + } + } + + if let Some(revalidation_result) = revalidation_result_rx.recv().await { + let start = Instant::now(); + let revalidated_len = revalidation_result.revalidated.len(); + let validated_pool = self.pool.validated_pool(); + validated_pool.remove_invalid(&revalidation_result.invalid_hashes); + if revalidated_len > 0 { + self.pool.resubmit(revalidation_result.revalidated); + } + + self.metrics.report(|metrics| { + let _ = ( + revalidation_result + .invalid_hashes + .len() + .try_into() + .map(|v| metrics.view_revalidation_invalid_txs.inc_by(v)), + revalidated_len + .try_into() + .map(|v| metrics.view_revalidation_resubmitted_txs.inc_by(v)), + ); + }); + + log::debug!( + target:LOG_TARGET, + "view::finish_revalidation: applying revalidation result invalid: {} revalidated: {} at {:?} took {:?}", + revalidation_result.invalid_hashes.len(), + revalidated_len, + self.at.hash, + start.elapsed() + ); + } + } +} 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 new file mode 100644 index 000000000000..f23dcedd5bfd --- /dev/null +++ b/substrate/client/transaction-pool/src/fork_aware_txpool/view_store.rs @@ -0,0 +1,487 @@ +// 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 . + +//! Transaction pool view store. Basically block hash to view map with some utility methods. + +use super::{ + multi_view_listener::{MultiViewListener, TxStatusStream}, + view::View, +}; +use crate::{ + fork_aware_txpool::dropped_watcher::MultiViewDroppedWatcherController, + graph, + graph::{base_pool::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 sp_blockchain::TreeRoute; +use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use std::{collections::HashMap, sync::Arc, time::Instant}; + +/// The helper structure encapsulates all the views. +pub(super) struct ViewStore +where + Block: BlockT, + ChainApi: graph::ChainApi, +{ + /// The blockchain api. + pub(super) api: Arc, + /// Active views at tips of the forks. + /// + /// Active views are updated with incoming transactions. + pub(super) active_views: RwLock>>>, + /// Inactive views at intermediary blocks that are no longer tips of the forks. + /// + /// Inactive views are not updated with incoming transactions, while they can still be used to + /// build new blocks upon them. + pub(super) inactive_views: RwLock>>>, + /// Listener for controlling external watchers of transactions. + /// + /// Provides a side-channel allowing to send per-transaction state changes notification. + pub(super) listener: Arc>, + /// Most recent block processed by tx-pool. Used in the API functions that were not changed to + /// add `at` parameter. + pub(super) most_recent_view: RwLock>, + /// The controller of multi view dropped stream. + pub(super) dropped_stream_controller: MultiViewDroppedWatcherController, +} + +impl ViewStore +where + Block: BlockT, + ChainApi: graph::ChainApi + 'static, + ::Hash: Unpin, +{ + /// Creates a new empty view store. + pub(super) fn new( + api: Arc, + listener: Arc>, + dropped_stream_controller: MultiViewDroppedWatcherController, + ) -> Self { + Self { + api, + active_views: Default::default(), + inactive_views: Default::default(), + listener, + most_recent_view: RwLock::from(None), + dropped_stream_controller, + } + } + + /// Imports a bunch of unverified extrinsics to every active view. + pub(super) async fn submit( + &self, + source: TransactionSource, + xts: impl IntoIterator> + Clone, + ) -> HashMap, ChainApi::Error>>> { + let submit_futures = { + let active_views = self.active_views.read(); + active_views + .iter() + .map(|(_, view)| { + let view = view.clone(); + let xts = xts.clone(); + async move { (view.at.hash, view.submit_many(source, xts).await) } + }) + .collect::>() + }; + let results = futures::future::join_all(submit_futures).await; + + HashMap::<_, _>::from_iter(results.into_iter()) + } + + /// Synchronously imports single unverified extrinsics into every active view. + pub(super) fn submit_local( + &self, + xt: ExtrinsicFor, + ) -> Result, ChainApi::Error> { + let active_views = self + .active_views + .read() + .iter() + .map(|(_, view)| view.clone()) + .collect::>(); + + let tx_hash = self.api.hash_and_length(&xt).0; + + let result = active_views + .iter() + .map(|view| view.submit_local(xt.clone())) + .find_or_first(Result::is_ok); + + if let Some(Err(err)) = result { + log::trace!(target: LOG_TARGET, "[{:?}] submit_local: err: {}", tx_hash, err); + return Err(err) + }; + + Ok(tx_hash) + } + + /// Import a single extrinsic and starts to watch its progress in the pool. + /// + /// The extrinsic is imported to every view, and the individual streams providing the progress + /// of this transaction within every view are added to the multi view listener. + /// + /// The external stream of aggregated/processed events provided by the `MultiViewListener` + /// instance is returned. + pub(super) async fn submit_and_watch( + &self, + _at: Block::Hash, + source: TransactionSource, + xt: ExtrinsicFor, + ) -> 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()) + }; + let submit_and_watch_futures = { + let active_views = self.active_views.read(); + active_views + .iter() + .map(|(_, view)| { + let view = view.clone(); + let xt = xt.clone(); + async move { + match view.submit_and_watch(source, xt).await { + Ok(watcher) => { + self.listener.add_view_watcher_for_tx( + tx_hash, + view.at.hash, + watcher.into_stream().boxed(), + ); + Ok(()) + }, + Err(e) => Err(e), + } + } + }) + .collect::>() + }; + let maybe_error = futures::future::join_all(submit_and_watch_futures) + .await + .into_iter() + .find_or_first(Result::is_ok); + + if let Some(Err(err)) = maybe_error { + log::trace!(target: LOG_TARGET, "[{:?}] submit_and_watch: err: {}", tx_hash, err); + return Err(err); + }; + + Ok(external_watcher) + } + + /// Returns the pool status for every active view. + pub(super) fn status(&self) -> HashMap { + self.active_views.read().iter().map(|(h, v)| (*h, v.status())).collect() + } + + /// Returns true if there are no active views. + pub(super) fn is_empty(&self) -> bool { + self.active_views.read().is_empty() && self.inactive_views.read().is_empty() + } + + /// Finds the best existing active view to clone from along the path. + /// + /// ```text + /// Tree route from R1 to E2. + /// <- R3 <- R2 <- R1 + /// / + /// C + /// \-> E1 -> E2 + /// ``` + /// ```text + /// Search path is: + /// [E1, C, R3, R2, R1] + /// ``` + pub(super) fn find_best_view( + &self, + tree_route: &TreeRoute, + ) -> Option>> { + let active_views = self.active_views.read(); + let best_view = { + tree_route + .retracted() + .iter() + .chain(std::iter::once(tree_route.common_block())) + .chain(tree_route.enacted().iter()) + .rev() + .find(|block| active_views.contains_key(&block.hash)) + }; + best_view.map(|h| { + active_views + .get(&h.hash) + .expect("hash was just found in the map's keys. qed") + .clone() + }) + } + + /// Returns an iterator for ready transactions for the most recently notified best block. + /// + /// The iterator for future transactions is returned if the most recently notified best block, + /// for which maintain process was accomplished, exists. + pub(super) fn ready(&self) -> ReadyIteratorFor { + let ready_iterator = self + .most_recent_view + .read() + .map(|at| self.get_view_at(at, true)) + .flatten() + .map(|(v, _)| v.pool.validated_pool().ready()); + + if let Some(ready_iterator) = ready_iterator { + return Box::new(ready_iterator) + } else { + return Box::new(std::iter::empty()) + } + } + + /// Returns a list of future transactions for the most recently notified best block. + /// + /// The set of future transactions is returned if the most recently notified best block, for + /// which maintain process was accomplished, exists. + pub(super) fn futures( + &self, + ) -> Vec, ExtrinsicFor>> { + self.most_recent_view + .read() + .map(|at| self.get_view_at(at, true)) + .flatten() + .map(|(v, _)| v.pool.validated_pool().pool.read().futures().cloned().collect()) + .unwrap_or_default() + } + + /// Collects all the transactions included in the blocks on the provided `tree_route` and + /// triggers finalization event for them. + /// + /// The finalization event is sent using side-channel of the multi view `listener`. + /// + /// Returns the list of finalized transactions hashes. + pub(super) async fn finalize_route( + &self, + finalized_hash: Block::Hash, + tree_route: &[Block::Hash], + ) -> Vec> { + log::trace!(target: LOG_TARGET, "finalize_route finalized_hash:{finalized_hash:?} tree_route: {tree_route:?}"); + + let mut finalized_transactions = Vec::new(); + + for block in tree_route.iter().chain(std::iter::once(&finalized_hash)) { + let extrinsics = self + .api + .block_body(*block) + .await + .unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Finalize route: error request: {}", e); + None + }) + .unwrap_or_default() + .iter() + .map(|e| self.api.hash_and_length(&e).0) + .collect::>(); + + extrinsics + .iter() + .enumerate() + .for_each(|(i, tx_hash)| self.listener.finalize_transaction(*tx_hash, *block, i)); + + finalized_transactions.extend(extrinsics); + } + + finalized_transactions + } + + /// Return specific ready transaction by hash, if there is one. + /// + /// Currently the ready transaction is returned if it exists for the most recently notified best + /// block (for which maintain process was accomplished). + pub(super) fn ready_transaction( + &self, + at: Block::Hash, + tx_hash: &ExtrinsicHash, + ) -> Option> { + self.active_views + .read() + .get(&at) + .and_then(|v| v.pool.validated_pool().ready_by_hash(tx_hash)) + } + + /// Inserts new view into the view store. + /// + /// All the views associated with the blocks which are on enacted path (including common + /// ancestor) will be: + /// - 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. + pub(super) async fn insert_new_view( + &self, + view: Arc>, + tree_route: &TreeRoute, + ) { + //note: most_recent_view must be synced with changes in in/active_views. + { + let mut most_recent_view_lock = self.most_recent_view.write(); + let mut active_views = self.active_views.write(); + let mut inactive_views = self.inactive_views.write(); + + std::iter::once(tree_route.common_block()) + .chain(tree_route.enacted().iter()) + .map(|block| block.hash) + .for_each(|hash| { + active_views.remove(&hash).map(|view| { + inactive_views.insert(hash, view); + }); + }); + active_views.insert(view.at.hash, view.clone()); + most_recent_view_lock.replace(view.at.hash); + }; + log::trace!(target:LOG_TARGET,"insert_new_view: inactive_views: {:?}", self.inactive_views.read().keys()); + } + + /// Returns an optional reference to the view at given hash. + /// + /// If `allow_retracted` flag is set, inactive views are also searched. + /// + /// If the view at provided hash does not exist `None` is returned. + pub(super) fn get_view_at( + &self, + at: Block::Hash, + allow_inactive: bool, + ) -> Option<(Arc>, bool)> { + if let Some(view) = self.active_views.read().get(&at) { + return Some((view.clone(), false)); + } + if allow_inactive { + if let Some(view) = self.inactive_views.read().get(&at) { + return Some((view.clone(), true)) + } + }; + None + } + + /// The pre-finalization event handle for the view store. + /// + /// This function removes the references to the views that will be removed during finalization + /// from the dropped stream controller. This will allow for correct dispatching of `Dropped` + /// events. + pub(crate) async fn handle_pre_finalized(&self, finalized_hash: Block::Hash) { + let finalized_number = self.api.block_id_to_number(&BlockId::Hash(finalized_hash)); + let mut removed_views = vec![]; + + { + self.active_views + .read() + .iter() + .filter(|(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, + }) + .map(|(_, v)| removed_views.push(v.at.hash)) + .for_each(drop); + } + + { + self.inactive_views + .read() + .iter() + .filter(|(_, v)| !match finalized_number { + Err(_) | Ok(None) => false, + Ok(Some(n)) => v.at.number >= n, + }) + .map(|(_, v)| removed_views.push(v.at.hash)) + .for_each(drop); + } + + log::trace!(target:LOG_TARGET,"handle_pre_finalized: removed_views: {:?}", removed_views); + + removed_views.iter().for_each(|view| { + self.dropped_stream_controller.remove_view(*view); + }); + } + + /// The finalization event handle for the view store. + /// + /// Views that have associated block number less than finalized block number are removed from + /// both active and inactive set. + /// + /// Note: the views with the associated number greater than finalized block number on the forks + /// that are not finalized will stay in the view store. They will be removed in the future, once + /// new finalized blocks will be notified. This is to avoid scanning for common ancestors. + /// + /// All watched transactions in the blocks from the tree_route will be notified with `Finalized` + /// event. + /// + /// Returns the list of hashes of all finalized transactions along the provided `tree_route`. + pub(crate) async fn handle_finalized( + &self, + finalized_hash: Block::Hash, + tree_route: &[Block::Hash], + ) -> Vec> { + let finalized_xts = self.finalize_route(finalized_hash, tree_route).await; + let finalized_number = self.api.block_id_to_number(&BlockId::Hash(finalized_hash)); + + //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(); + inactive_views.retain(|_, v| match finalized_number { + Err(_) | Ok(None) => false, + Ok(Some(n)) => v.at.number >= n, + }); + + log::trace!(target:LOG_TARGET,"handle_finalized: inactive_views: {:?}", inactive_views.keys()); + } + + self.listener.remove_view(finalized_hash); + self.listener.remove_stale_controllers(); + self.dropped_stream_controller.remove_finalized_txs(finalized_xts.clone()); + + finalized_xts + } + + /// Terminates all the ongoing background views revalidations triggered at the end of maintain + /// process. + /// + /// Refer to [*View revalidation*](../index.html#view-revalidation) for more details. + pub(crate) async fn finish_background_revalidations(&self) { + let start = Instant::now(); + let finish_revalidation_futures = { + let active_views = self.active_views.read(); + active_views + .iter() + .map(|(_, view)| { + let view = view.clone(); + async move { view.finish_revalidation().await } + }) + .collect::>() + }; + futures::future::join_all(finish_revalidation_futures).await; + log::trace!(target:LOG_TARGET,"finish_background_revalidations took {:?}", start.elapsed()); + } +} diff --git a/substrate/client/transaction-pool/src/graph/base_pool.rs b/substrate/client/transaction-pool/src/graph/base_pool.rs index 32885622da42..e4c3a6c425a9 100644 --- a/substrate/client/transaction-pool/src/graph/base_pool.rs +++ b/substrate/client/transaction-pool/src/graph/base_pool.rs @@ -23,7 +23,7 @@ use std::{cmp::Ordering, collections::HashSet, fmt, hash, sync::Arc}; use crate::LOG_TARGET; -use log::{debug, trace, warn}; +use log::{trace, warn}; use sc_transaction_pool_api::{error, InPoolTransaction, PoolStatus}; use serde::Serialize; use sp_core::hexdisplay::HexDisplay; @@ -207,7 +207,7 @@ const RECENTLY_PRUNED_TAGS: usize = 2; /// as-is for the second time will fail or produce unwanted results. /// Most likely it is required to revalidate them and recompute set of /// required tags. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct BasePool { reject_future_transactions: bool, future: FutureTransactions, @@ -238,6 +238,12 @@ impl BasePool BasePool BasePool if first { - debug!(target: LOG_TARGET, "[{:?}] Error importing: {:?}", current_hash, e); + trace!(target: LOG_TARGET, "[{:?}] Error importing: {:?}", current_hash, e); return Err(e) } else { failed.push(current_hash); @@ -347,7 +353,7 @@ impl BasePool BasePool Vec>> { let mut removed = self.ready.remove_subtree(hashes); @@ -463,8 +469,8 @@ impl BasePool) -> PruneStatus { @@ -474,6 +480,9 @@ impl BasePool>(); + let futures_removed = self.future.prune_tags(&tags); + for tag in tags { // make sure to promote any future transactions that could be unlocked to_import.append(&mut self.future.satisfy_tags(std::iter::once(&tag))); @@ -485,6 +494,10 @@ impl BasePool> = Transaction { - data: vec![], - bytes: 1, - hash: 1u64, - priority: 5u64, - valid_till: 64u64, - requires: vec![], - provides: vec![], - propagate: true, - source: Source::External, - }; + fn default_tx() -> Transaction> { + Transaction { + data: vec![], + bytes: 1, + hash: 1u64, + priority: 5u64, + valid_till: 64u64, + requires: vec![], + provides: vec![], + propagate: true, + source: Source::External, + } + } + + #[test] + fn prune_for_ready_works() { + // given + let mut pool = pool(); + + // when + pool.import(Transaction { + data: vec![1u8].into(), + provides: vec![vec![2]], + ..default_tx().clone() + }) + .unwrap(); + + // then + assert_eq!(pool.ready().count(), 1); + assert_eq!(pool.ready.len(), 1); + + let result = pool.prune_tags(vec![vec![2]]); + assert_eq!(pool.ready().count(), 0); + assert_eq!(pool.ready.len(), 0); + assert_eq!(result.pruned.len(), 1); + assert_eq!(result.failed.len(), 0); + assert_eq!(result.promoted.len(), 0); + } + + #[test] + fn prune_for_future_works() { + // given + let mut pool = pool(); + + // when + pool.import(Transaction { + data: vec![1u8].into(), + requires: vec![vec![1]], + provides: vec![vec![2]], + hash: 0xaa, + ..default_tx().clone() + }) + .unwrap(); + + // then + assert_eq!(pool.futures().count(), 1); + assert_eq!(pool.future.len(), 1); + + let result = pool.prune_tags(vec![vec![2]]); + assert_eq!(pool.ready().count(), 0); + assert_eq!(pool.ready.len(), 0); + assert_eq!(pool.futures().count(), 0); + assert_eq!(pool.future.len(), 0); + + assert_eq!(result.pruned.len(), 0); + assert_eq!(result.failed.len(), 1); + assert_eq!(result.failed[0], 0xaa); + assert_eq!(result.promoted.len(), 0); + } #[test] fn should_import_transaction_to_ready() { @@ -557,8 +628,12 @@ mod tests { let mut pool = pool(); // when - pool.import(Transaction { data: vec![1u8], provides: vec![vec![1]], ..DEFAULT_TX.clone() }) - .unwrap(); + pool.import(Transaction { + data: vec![1u8].into(), + provides: vec![vec![1]], + ..default_tx().clone() + }) + .unwrap(); // then assert_eq!(pool.ready().count(), 1); @@ -571,10 +646,18 @@ mod tests { let mut pool = pool(); // when - pool.import(Transaction { data: vec![1u8], provides: vec![vec![1]], ..DEFAULT_TX.clone() }) - .unwrap(); - pool.import(Transaction { data: vec![1u8], provides: vec![vec![1]], ..DEFAULT_TX.clone() }) - .unwrap_err(); + pool.import(Transaction { + data: vec![1u8].into(), + provides: vec![vec![1]], + ..default_tx().clone() + }) + .unwrap(); + pool.import(Transaction { + data: vec![1u8].into(), + provides: vec![vec![1]], + ..default_tx().clone() + }) + .unwrap_err(); // then assert_eq!(pool.ready().count(), 1); @@ -588,19 +671,19 @@ mod tests { // when pool.import(Transaction { - data: vec![1u8], + data: vec![1u8].into(), requires: vec![vec![0]], provides: vec![vec![1]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); assert_eq!(pool.ready().count(), 0); assert_eq!(pool.ready.len(), 0); pool.import(Transaction { - data: vec![2u8], + data: vec![2u8].into(), hash: 2, provides: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); @@ -616,33 +699,33 @@ mod tests { // when pool.import(Transaction { - data: vec![1u8], + data: vec![1u8].into(), requires: vec![vec![0]], provides: vec![vec![1]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![3u8], + data: vec![3u8].into(), hash: 3, requires: vec![vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![2u8], + data: vec![2u8].into(), hash: 2, requires: vec![vec![1]], provides: vec![vec![3], vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1_000u64, requires: vec![vec![3], vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); assert_eq!(pool.ready().count(), 0); @@ -650,10 +733,10 @@ mod tests { let res = pool .import(Transaction { - data: vec![5u8], + data: vec![5u8].into(), hash: 5, provides: vec![vec![0], vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); @@ -682,18 +765,18 @@ mod tests { // given let mut pool = pool(); pool.import(Transaction { - data: vec![1u8], + data: vec![1u8].into(), requires: vec![vec![0]], provides: vec![vec![1]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![3u8], + data: vec![3u8].into(), hash: 3, requires: vec![vec![1]], provides: vec![vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); assert_eq!(pool.ready().count(), 0); @@ -701,11 +784,11 @@ mod tests { // when pool.import(Transaction { - data: vec![2u8], + data: vec![2u8].into(), hash: 2, requires: vec![vec![2]], provides: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); @@ -720,11 +803,11 @@ mod tests { // let's close the cycle with one additional transaction let res = pool .import(Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 50u64, provides: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); let mut it = pool.ready().into_iter().map(|tx| tx.data[0]); @@ -744,18 +827,18 @@ mod tests { // given let mut pool = pool(); pool.import(Transaction { - data: vec![1u8], + data: vec![1u8].into(), requires: vec![vec![0]], provides: vec![vec![1]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![3u8], + data: vec![3u8].into(), hash: 3, requires: vec![vec![1]], provides: vec![vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); assert_eq!(pool.ready().count(), 0); @@ -763,11 +846,11 @@ mod tests { // when pool.import(Transaction { - data: vec![2u8], + data: vec![2u8].into(), hash: 2, requires: vec![vec![2]], provides: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); @@ -782,11 +865,11 @@ mod tests { // let's close the cycle with one additional transaction let err = pool .import(Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1u64, // lower priority than Tx(2) provides: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap_err(); let mut it = pool.ready().into_iter().map(|tx| tx.data[0]); @@ -804,49 +887,49 @@ mod tests { // given let mut pool = pool(); pool.import(Transaction { - data: vec![5u8], + data: vec![5u8].into(), hash: 5, provides: vec![vec![0], vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![1u8], + data: vec![1u8].into(), requires: vec![vec![0]], provides: vec![vec![1]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![3u8], + data: vec![3u8].into(), hash: 3, requires: vec![vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![2u8], + data: vec![2u8].into(), hash: 2, requires: vec![vec![1]], provides: vec![vec![3], vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1_000u64, requires: vec![vec![3], vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); // future pool.import(Transaction { - data: vec![6u8], + data: vec![6u8].into(), hash: 6, priority: 1_000u64, requires: vec![vec![11]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); assert_eq!(pool.ready().count(), 5); @@ -866,39 +949,43 @@ mod tests { let mut pool = pool(); // future (waiting for 0) pool.import(Transaction { - data: vec![5u8], + data: vec![5u8].into(), hash: 5, requires: vec![vec![0]], provides: vec![vec![100]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); // ready - pool.import(Transaction { data: vec![1u8], provides: vec![vec![1]], ..DEFAULT_TX.clone() }) - .unwrap(); pool.import(Transaction { - data: vec![2u8], + data: vec![1u8].into(), + provides: vec![vec![1]], + ..default_tx().clone() + }) + .unwrap(); + pool.import(Transaction { + data: vec![2u8].into(), hash: 2, requires: vec![vec![2]], provides: vec![vec![3]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![3u8], + data: vec![3u8].into(), hash: 3, requires: vec![vec![1]], provides: vec![vec![2]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); pool.import(Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1_000u64, requires: vec![vec![3], vec![2]], provides: vec![vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); @@ -927,12 +1014,12 @@ mod tests { format!( "{:?}", Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1_000u64, requires: vec![vec![3], vec![2]], provides: vec![vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() } ), "Transaction { \ @@ -946,12 +1033,12 @@ source: TransactionSource::External, requires: [03, 02], provides: [04], data: [ fn transaction_propagation() { assert_eq!( Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1_000u64, requires: vec![vec![3], vec![2]], provides: vec![vec![4]], - ..DEFAULT_TX.clone() + ..default_tx().clone() } .is_propagable(), true @@ -959,13 +1046,13 @@ source: TransactionSource::External, requires: [03, 02], provides: [04], data: [ assert_eq!( Transaction { - data: vec![4u8], + data: vec![4u8].into(), hash: 4, priority: 1_000u64, requires: vec![vec![3], vec![2]], provides: vec![vec![4]], propagate: false, - ..DEFAULT_TX.clone() + ..default_tx().clone() } .is_propagable(), false @@ -982,10 +1069,10 @@ source: TransactionSource::External, requires: [03, 02], provides: [04], data: [ // then let err = pool.import(Transaction { - data: vec![5u8], + data: vec![5u8].into(), hash: 5, requires: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }); if let Err(error::Error::RejectedFutureTransaction) = err { @@ -1001,10 +1088,10 @@ source: TransactionSource::External, requires: [03, 02], provides: [04], data: [ // when pool.import(Transaction { - data: vec![5u8], + data: vec![5u8].into(), hash: 5, requires: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); @@ -1027,10 +1114,10 @@ source: TransactionSource::External, requires: [03, 02], provides: [04], data: [ // when let flag_value = pool.with_futures_enabled(|pool, flag| { pool.import(Transaction { - data: vec![5u8], + data: vec![5u8].into(), hash: 5, requires: vec![vec![0]], - ..DEFAULT_TX.clone() + ..default_tx().clone() }) .unwrap(); diff --git a/substrate/client/transaction-pool/src/graph/future.rs b/substrate/client/transaction-pool/src/graph/future.rs index bad466318485..2c1e64c04b7f 100644 --- a/substrate/client/transaction-pool/src/graph/future.rs +++ b/substrate/client/transaction-pool/src/graph/future.rs @@ -27,6 +27,7 @@ use sp_runtime::transaction_validity::TransactionTag as Tag; use std::time::Instant; use super::base_pool::Transaction; +use crate::{common::log_xt::log_xt_trace, LOG_TARGET}; /// Transaction with partially satisfied dependencies. pub struct WaitingTransaction { @@ -105,11 +106,11 @@ impl WaitingTransaction { /// A pool of transactions that are not yet ready to be included in the block. /// -/// Contains transactions that are still awaiting for some other transactions that +/// Contains transactions that are still awaiting some other transactions that /// could provide a tag that they require. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct FutureTransactions { - /// tags that are not yet provided by any transaction and we await for them + /// tags that are not yet provided by any transaction, and we await for them wanted_tags: HashMap>, /// Transactions waiting for a particular other transaction waiting: HashMap>, @@ -128,7 +129,9 @@ every hash from `wanted_tags` is always present in `waiting`; qed #"; -impl FutureTransactions { +impl + FutureTransactions +{ /// Import transaction to Future queue. /// /// Only transactions that don't have all their tags satisfied should occupy @@ -165,10 +168,30 @@ impl FutureTransactions { .collect() } + /// Removes transactions that provide any of tags in the given list. + /// + /// Returns list of removed transactions. + pub fn prune_tags(&mut self, tags: &Vec) -> Vec>> { + let pruned = self + .waiting + .values() + .filter_map(|tx| { + tx.transaction + .provides + .iter() + .any(|provided_tag| tags.contains(provided_tag)) + .then(|| tx.transaction.hash.clone()) + }) + .collect::>(); + + log_xt_trace!(target: LOG_TARGET, &pruned, "[{:?}] FutureTransactions: removed while pruning tags."); + self.remove(&pruned) + } + /// Satisfies provided tags in transactions that are waiting for them. /// /// Returns (and removes) transactions that became ready after their last tag got - /// satisfied and now we can remove them from Future and move to Ready queue. + /// satisfied, and now we can remove them from Future and move to Ready queue. pub fn satisfy_tags>( &mut self, tags: impl IntoIterator, @@ -218,6 +241,7 @@ impl FutureTransactions { removed.push(waiting_tx.transaction) } } + removed } diff --git a/substrate/client/transaction-pool/src/graph/listener.rs b/substrate/client/transaction-pool/src/graph/listener.rs index 46b7957e0b31..a5593920eec4 100644 --- a/substrate/client/transaction-pool/src/graph/listener.rs +++ b/substrate/client/transaction-pool/src/graph/listener.rs @@ -18,18 +18,31 @@ use std::{collections::HashMap, fmt::Debug, hash}; -use crate::LOG_TARGET; use linked_hash_map::LinkedHashMap; -use log::{debug, trace}; +use log::trace; +use sc_transaction_pool_api::TransactionStatus; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use serde::Serialize; use sp_runtime::traits; use super::{watcher, BlockHash, ChainApi, ExtrinsicHash}; +static LOG_TARGET: &str = "txpool::watcher"; + +/// Single event used in dropped by limits stream. It is one of Ready/Future/Dropped. +pub type DroppedByLimitsEvent = (H, TransactionStatus); +/// Stream of events used to determine if a transaction was dropped. +pub type DroppedByLimitsStream = TracingUnboundedReceiver>; + /// Extrinsic pool default listener. pub struct Listener { - watchers: HashMap>>, + watchers: HashMap>>, finality_watchers: LinkedHashMap, Vec>, + + /// The sink used to notify dropped-by-enforcing-limits transactions. Also ready and future + /// statuses are reported via this channel to allow consumer of the stream tracking actual + /// drops. + dropped_by_limits_sink: Option>>>, } /// Maximum number of blocks awaiting finality at any time. @@ -37,11 +50,15 @@ const MAX_FINALITY_WATCHERS: usize = 512; impl Default for Listener { fn default() -> Self { - Self { watchers: Default::default(), finality_watchers: Default::default() } + Self { + watchers: Default::default(), + finality_watchers: Default::default(), + dropped_by_limits_sink: None, + } } } -impl Listener { +impl Listener { fn fire(&mut self, hash: &H, fun: F) where F: FnOnce(&mut watcher::Sender>), @@ -66,6 +83,15 @@ impl Listener { sender.new_watcher(hash) } + /// Creates a new single stream for entire pool. + /// + /// The stream can be used to subscribe to life-cycle events of all extrinsics in the pool. + pub fn create_dropped_by_limits_stream(&mut self) -> DroppedByLimitsStream> { + let (sender, single_stream) = tracing_unbounded("mpsc_txpool_watcher", 100_000); + self.dropped_by_limits_sink = Some(sender); + single_stream + } + /// Notify the listeners about extrinsic broadcast. pub fn broadcasted(&mut self, hash: &H, peers: Vec) { trace!(target: LOG_TARGET, "[{:?}] Broadcasted", hash); @@ -79,32 +105,55 @@ impl Listener { if let Some(old) = old { self.fire(old, |watcher| watcher.usurped(tx.clone())); } + + if let Some(ref sink) = self.dropped_by_limits_sink { + if let Err(e) = sink.unbounded_send((tx.clone(), TransactionStatus::Ready)) { + trace!(target: LOG_TARGET, "[{:?}] dropped_sink/ready: send message failed: {:?}", tx, e); + } + } } /// New transaction was added to the future pool. pub fn future(&mut self, tx: &H) { trace!(target: LOG_TARGET, "[{:?}] Future", tx); self.fire(tx, |watcher| watcher.future()); + if let Some(ref sink) = self.dropped_by_limits_sink { + if let Err(e) = sink.unbounded_send((tx.clone(), TransactionStatus::Future)) { + trace!(target: LOG_TARGET, "[{:?}] dropped_sink/future: send message failed: {:?}", tx, e); + } + } } /// Transaction was dropped from the pool because of the limit. - pub fn dropped(&mut self, tx: &H, by: Option<&H>) { + /// + /// If the function was actually called due to enforcing limits, the `limits_enforced` flag + /// shall be set to true. + pub fn dropped(&mut self, tx: &H, by: Option<&H>, limits_enforced: bool) { 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); + } + } + } } /// Transaction was removed as invalid. pub fn invalid(&mut self, tx: &H) { - debug!(target: LOG_TARGET, "[{:?}] Extrinsic invalid", tx); + trace!(target: LOG_TARGET, "[{:?}] Extrinsic invalid", tx); self.fire(tx, |watcher| watcher.invalid()); } /// Transaction was pruned from the pool. pub fn pruned(&mut self, block_hash: BlockHash, tx: &H) { - debug!(target: LOG_TARGET, "[{:?}] Pruned at {:?}", tx, block_hash); + trace!(target: LOG_TARGET, "[{:?}] Pruned at {:?}", tx, block_hash); // Get the transactions included in the given block hash. let txs = self.finality_watchers.entry(block_hash).or_insert(vec![]); txs.push(tx.clone()); @@ -135,7 +184,7 @@ impl Listener { pub fn finalized(&mut self, block_hash: BlockHash) { if let Some(hashes) = self.finality_watchers.remove(&block_hash) { for (tx_index, hash) in hashes.into_iter().enumerate() { - log::debug!( + log::trace!( target: LOG_TARGET, "[{:?}] Sent finalization event (block {:?})", hash, @@ -145,4 +194,9 @@ impl Listener { } } } + + /// Provides hashes of all watched transactions. + pub fn watched_transactions(&self) -> impl Iterator { + self.watchers.keys() + } } diff --git a/substrate/client/transaction-pool/src/graph/mod.rs b/substrate/client/transaction-pool/src/graph/mod.rs index 484a6d6cf9f0..d93898b1b22a 100644 --- a/substrate/client/transaction-pool/src/graph/mod.rs +++ b/substrate/client/transaction-pool/src/graph/mod.rs @@ -31,14 +31,16 @@ mod listener; mod pool; mod ready; mod rotator; -mod tracked_map; +pub(crate) mod tracked_map; mod validated_pool; pub mod base_pool; pub mod watcher; -pub use self::{ - base_pool::Transaction, - pool::{BlockHash, ChainApi, ExtrinsicFor, ExtrinsicHash, NumberFor, Options, Pool}, +pub use self::pool::{ + BlockHash, ChainApi, ExtrinsicFor, ExtrinsicHash, NumberFor, Options, Pool, RawExtrinsicFor, + TransactionFor, ValidatedTransactionFor, }; pub use validated_pool::{IsValidator, ValidatedTransaction}; + +pub(crate) use listener::DroppedByLimitsEvent; diff --git a/substrate/client/transaction-pool/src/graph/pool.rs b/substrate/client/transaction-pool/src/graph/pool.rs index 5305b5f1c12e..2dd8de352c6b 100644 --- a/substrate/client/transaction-pool/src/graph/pool.rs +++ b/substrate/client/transaction-pool/src/graph/pool.rs @@ -16,12 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::HashMap, sync::Arc, time::Duration}; - -use crate::LOG_TARGET; +use crate::{common::log_xt::log_xt_trace, LOG_TARGET}; use futures::{channel::mpsc::Receiver, Future}; +use indexmap::IndexMap; use sc_transaction_pool_api::error; -use sp_blockchain::TreeRoute; +use sp_blockchain::{HashAndNumber, TreeRoute}; use sp_runtime::{ generic::BlockId, traits::{self, Block as BlockT, SaturatedConversion}, @@ -29,7 +28,11 @@ use sp_runtime::{ TransactionSource, TransactionTag as Tag, TransactionValidity, TransactionValidityError, }, }; -use std::time::Instant; +use std::{ + collections::HashMap, + sync::Arc, + time::{Duration, Instant}, +}; use super::{ base_pool as base, @@ -44,8 +47,10 @@ pub type EventStream = Receiver; pub type BlockHash = <::Block as traits::Block>::Hash; /// Extrinsic hash type for a pool. pub type ExtrinsicHash = <::Block as traits::Block>::Hash; -/// Extrinsic type for a pool. -pub type ExtrinsicFor = <::Block as traits::Block>::Extrinsic; +/// Extrinsic type for a pool (reference counted). +pub type ExtrinsicFor = Arc<<::Block as traits::Block>::Extrinsic>; +/// Extrinsic type for a pool (raw data). +pub type RawExtrinsicFor = <::Block as traits::Block>::Extrinsic; /// Block number type for the ChainApi pub type NumberFor = traits::NumberFor<::Block>; /// A type of transaction stored in the pool @@ -68,7 +73,7 @@ pub trait ChainApi: Send + Sync { + Send + 'static; - /// Verify extrinsic at given block. + /// Asynchronously verify extrinsic at given block. fn validate_transaction( &self, at: ::Hash, @@ -76,6 +81,17 @@ pub trait ChainApi: Send + Sync { uxt: ExtrinsicFor, ) -> Self::ValidationFuture; + /// Synchronously verify given extrinsic at given block. + /// + /// Validates a transaction by calling into the runtime. Same as `validate_transaction` but + /// blocks the current thread when performing validation. + fn validate_transaction_blocking( + &self, + at: ::Hash, + source: TransactionSource, + uxt: ExtrinsicFor, + ) -> Result; + /// Returns a block number given the block id. fn block_id_to_number( &self, @@ -89,7 +105,7 @@ pub trait ChainApi: Send + Sync { ) -> Result::Hash>, Self::Error>; /// Returns hash and encoding length of the extrinsic. - fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (ExtrinsicHash, usize); + fn hash_and_length(&self, uxt: &RawExtrinsicFor) -> (ExtrinsicHash, usize); /// Returns a block body given the block. fn block_body(&self, at: ::Hash) -> Self::BodyFuture; @@ -106,6 +122,16 @@ pub trait ChainApi: Send + Sync { from: ::Hash, to: ::Hash, ) -> Result, Self::Error>; + + /// Resolves block number by id. + fn resolve_block_number( + &self, + at: ::Hash, + ) -> Result, Self::Error> { + self.block_id_to_number(&BlockId::Hash(at)).and_then(|number| { + number.ok_or_else(|| error::Error::InvalidBlockId(format!("{:?}", at)).into()) + }) + } } /// Pool configuration options. @@ -154,13 +180,13 @@ impl Pool { /// Imports a bunch of unverified extrinsics to the pool pub async fn submit_at( &self, - at: ::Hash, + at: &HashAndNumber, source: TransactionSource, xts: impl IntoIterator>, - ) -> Result, B::Error>>, B::Error> { + ) -> Vec, B::Error>> { let xts = xts.into_iter().map(|xt| (source, xt)); - let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::Yes).await?; - Ok(self.validated_pool.submit(validated_transactions.into_values())) + let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::Yes).await; + self.validated_pool.submit(validated_transactions.into_values()) } /// Resubmit the given extrinsics to the pool. @@ -168,36 +194,35 @@ impl Pool { /// This does not check if a transaction is banned, before we verify it again. pub async fn resubmit_at( &self, - at: ::Hash, + at: &HashAndNumber, source: TransactionSource, xts: impl IntoIterator>, - ) -> Result, B::Error>>, B::Error> { + ) -> Vec, B::Error>> { let xts = xts.into_iter().map(|xt| (source, xt)); - let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::No).await?; - Ok(self.validated_pool.submit(validated_transactions.into_values())) + let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::No).await; + self.validated_pool.submit(validated_transactions.into_values()) } /// Imports one unverified extrinsic to the pool pub async fn submit_one( &self, - at: ::Hash, + at: &HashAndNumber, source: TransactionSource, xt: ExtrinsicFor, ) -> Result, B::Error> { - let res = self.submit_at(at, source, std::iter::once(xt)).await?.pop(); + let res = self.submit_at(at, source, std::iter::once(xt)).await.pop(); res.expect("One extrinsic passed; one result returned; qed") } /// Import a single extrinsic and starts to watch its progress in the pool. pub async fn submit_and_watch( &self, - at: ::Hash, + at: &HashAndNumber, source: TransactionSource, xt: ExtrinsicFor, ) -> Result, ExtrinsicHash>, B::Error> { - let block_number = self.resolve_block_number(&BlockId::Hash(at))?; let (_, tx) = self - .verify_one(at, block_number, source, xt, CheckBannedBeforeVerify::Yes) + .verify_one(at.hash, at.number, source, xt, CheckBannedBeforeVerify::Yes) .await; self.validated_pool.submit_and_watch(tx) } @@ -209,7 +234,7 @@ impl Pool { ) { let now = Instant::now(); self.validated_pool.resubmit(revalidated_transactions); - log::debug!( + log::trace!( target: LOG_TARGET, "Resubmitted. Took {} ms. Status: {:?}", now.elapsed().as_millis(), @@ -222,34 +247,30 @@ impl Pool { /// Used to clear the pool from transactions that were part of recently imported block. /// The main difference from the `prune` is that we do not revalidate any transactions /// and ignore unknown passed hashes. - pub fn prune_known( - &self, - at: &BlockId, - hashes: &[ExtrinsicHash], - ) -> Result<(), B::Error> { + pub fn prune_known(&self, at: &HashAndNumber, hashes: &[ExtrinsicHash]) { // Get details of all extrinsics that are already in the pool let in_pool_tags = self.validated_pool.extrinsics_tags(hashes).into_iter().flatten().flatten(); // Prune all transactions that provide given tags - let prune_status = self.validated_pool.prune_tags(in_pool_tags)?; + let prune_status = self.validated_pool.prune_tags(in_pool_tags); let pruned_transactions = hashes.iter().cloned().chain(prune_status.pruned.iter().map(|tx| tx.hash)); - self.validated_pool.fire_pruned(at, pruned_transactions) + self.validated_pool.fire_pruned(at, pruned_transactions); } /// Prunes ready transactions. /// /// Used to clear the pool from transactions that were part of recently imported block. /// To perform pruning we need the tags that each extrinsic provides and to avoid calling - /// into runtime too often we first lookup all extrinsics that are in the pool and get + /// into runtime too often we first look up all extrinsics that are in the pool and get /// their provided tags from there. Otherwise we query the runtime at the `parent` block. pub async fn prune( &self, - at: ::Hash, + at: &HashAndNumber, parent: ::Hash, - extrinsics: &[ExtrinsicFor], - ) -> Result<(), B::Error> { + extrinsics: &[RawExtrinsicFor], + ) { log::debug!( target: LOG_TARGET, "Starting pruning of block {:?} (extrinsics: {})", @@ -264,6 +285,7 @@ impl Pool { // Zip the ones from the pool with the full list (we get pairs `(Extrinsic, // Option>)`) let all = extrinsics.iter().zip(in_pool_tags.into_iter()); + let mut validated_counter: usize = 0; let mut future_tags = Vec::new(); for (extrinsic, in_pool_tags) in all { @@ -275,16 +297,19 @@ impl Pool { None => { // Avoid validating block txs if the pool is empty if !self.validated_pool.status().is_empty() { + validated_counter = validated_counter + 1; let validity = self .validated_pool .api() .validate_transaction( parent, TransactionSource::InBlock, - extrinsic.clone(), + Arc::from(extrinsic.clone()), ) .await; + log::trace!(target: LOG_TARGET,"[{:?}] prune::revalidated {:?}", self.validated_pool.api().hash_and_length(&extrinsic.clone()).0, validity); + if let Ok(Ok(validity)) = validity { future_tags.extend(validity.provides); } @@ -298,6 +323,8 @@ impl Pool { } } + log::trace!(target: LOG_TARGET,"prune: validated_counter:{validated_counter}"); + self.prune_tags(at, future_tags, in_pool_hashes).await } @@ -324,13 +351,13 @@ impl Pool { /// prevent importing them in the (near) future. pub async fn prune_tags( &self, - at: ::Hash, + at: &HashAndNumber, tags: impl IntoIterator, known_imported_hashes: impl IntoIterator> + Clone, - ) -> Result<(), B::Error> { - log::debug!(target: LOG_TARGET, "Pruning at {:?}", at); + ) { + log::trace!(target: LOG_TARGET, "Pruning at {:?}", at); // Prune all transactions that provide given tags - let prune_status = self.validated_pool.prune_tags(tags)?; + let prune_status = self.validated_pool.prune_tags(tags); // Make sure that we don't revalidate extrinsics that were part of the recently // imported block. This is especially important for UTXO-like chains cause the @@ -340,18 +367,20 @@ 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_hashes = prune_status.pruned.iter().map(|tx| tx.hash).collect::>(); let pruned_transactions = prune_status.pruned.into_iter().map(|tx| (tx.source, tx.data.clone())); let reverified_transactions = - self.verify(at, pruned_transactions, CheckBannedBeforeVerify::Yes).await?; + self.verify(at, pruned_transactions, CheckBannedBeforeVerify::Yes).await; - log::trace!(target: LOG_TARGET, "Pruning at {:?}. Resubmitting transactions.", at); - // And finally - submit reverified transactions back to the pool + let pruned_hashes = reverified_transactions.keys().map(Clone::clone).collect(); + + log::trace!(target: LOG_TARGET, "Pruning at {:?}. Resubmitting transactions: {}", &at, reverified_transactions.len()); + log_xt_trace!(data: tuple, target: LOG_TARGET, &reverified_transactions, "[{:?}] Resubmitting transaction: {:?}"); + // And finally - submit reverified transactions back to the pool self.validated_pool.resubmit_pruned( - &BlockId::Hash(at), + &at, known_imported_hashes, pruned_hashes, reverified_transactions.into_values().collect(), @@ -359,36 +388,28 @@ impl Pool { } /// Returns transaction hash - pub fn hash_of(&self, xt: &ExtrinsicFor) -> ExtrinsicHash { + pub fn hash_of(&self, xt: &RawExtrinsicFor) -> ExtrinsicHash { self.validated_pool.api().hash_and_length(xt).0 } - /// Resolves block number by id. - fn resolve_block_number(&self, at: &BlockId) -> Result, B::Error> { - self.validated_pool.api().block_id_to_number(at).and_then(|number| { - number.ok_or_else(|| error::Error::InvalidBlockId(format!("{:?}", at)).into()) - }) - } - /// Returns future that validates a bunch of transactions at given block. async fn verify( &self, - at: ::Hash, + at: &HashAndNumber, xts: impl IntoIterator)>, check: CheckBannedBeforeVerify, - ) -> Result, ValidatedTransactionFor>, B::Error> { - // we need a block number to compute tx validity - let block_number = self.resolve_block_number(&BlockId::Hash(at))?; + ) -> IndexMap, ValidatedTransactionFor> { + let HashAndNumber { number, hash } = *at; let res = futures::future::join_all( xts.into_iter() - .map(|(source, xt)| self.verify_one(at, block_number, source, xt, check)), + .map(|(source, xt)| self.verify_one(hash, number, source, xt, check)), ) .await .into_iter() - .collect::>(); + .collect::>(); - Ok(res) + res } /// Returns future that validates single transaction at given block. @@ -441,22 +462,31 @@ impl Pool { (hash, validity) } - /// get a reference to the underlying validated pool. + /// Get a reference to the underlying validated pool. pub fn validated_pool(&self) -> &ValidatedPool { &self.validated_pool } + + /// Clears the recently pruned transactions in validated pool. + pub fn clear_recently_pruned(&mut self) { + self.validated_pool.pool.write().clear_recently_pruned(); + } } -impl Clone for Pool { - fn clone(&self) -> Self { - Self { validated_pool: self.validated_pool.clone() } +impl Pool { + /// Deep clones the pool. + /// + /// Must be called on purpose: it duplicates all the internal structures. + pub fn deep_clone(&self) -> Self { + let other: ValidatedPool = (*self.validated_pool).clone(); + Self { validated_pool: Arc::from(other) } } } #[cfg(test)] mod tests { use super::{super::base_pool::Limit, *}; - use crate::tests::{pool, uxt, TestApi, INVALID_NONCE}; + use crate::common::tests::{pool, uxt, TestApi, INVALID_NONCE}; use assert_matches::assert_matches; use codec::Encode; use futures::executor::block_on; @@ -475,22 +505,58 @@ mod tests { let (pool, api) = pool(); // when - let hash = block_on(pool.submit_one( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + let hash = block_on( + pool.submit_one( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); // then assert_eq!(pool.validated_pool().ready().map(|v| v.hash).collect::>(), vec![hash]); } + #[test] + fn submit_at_preserves_order() { + sp_tracing::try_init_simple(); + // given + let (pool, api) = pool(); + + let txs = (0..10) + .map(|i| { + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(i)), + amount: 5, + nonce: i, + }) + .into() + }) + .collect::>(); + + 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)); + log::debug!("--> {hashes:#?}"); + + // then + hashes.into_iter().zip(initial_hashes.into_iter()).for_each( + |(result_hash, initial_hash)| { + assert_eq!(result_hash.unwrap(), initial_hash); + }, + ); + } + #[test] fn should_reject_if_temporarily_banned() { // given @@ -504,7 +570,7 @@ mod tests { // when pool.validated_pool.ban(&Instant::now(), vec![pool.hash_of(&uxt)]); - let res = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt)); + let res = block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.into())); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); @@ -527,7 +593,7 @@ mod tests { let uxt = ExtrinsicBuilder::new_include_data(vec![42]).build(); // when - let res = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt)); + let res = block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.into())); // then assert_matches!(res.unwrap_err(), error::Error::Unactionable); @@ -538,43 +604,52 @@ mod tests { let (stream, hash0, hash1) = { // given let (pool, api) = pool(); - let hash_of_block0 = api.expect_hash_from_number(0); + let han_of_block0 = api.expect_hash_and_number(0); let stream = pool.validated_pool().import_notification_stream(); // when - let hash0 = block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + let hash0 = block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); - let hash1 = block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 1, - }), - )) + let hash1 = block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 1, + }) + .into(), + ), + ) .unwrap(); // future doesn't count - let _hash = block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 3, - }), - )) + let _hash = block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 3, + }) + .into(), + ), + ) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 2); @@ -594,43 +669,52 @@ mod tests { fn should_clear_stale_transactions() { // given let (pool, api) = pool(); - let hash_of_block0 = api.expect_hash_from_number(0); - let hash1 = block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + let han_of_block0 = api.expect_hash_and_number(0); + let hash1 = block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); - let hash2 = block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 1, - }), - )) + let hash2 = block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 1, + }) + .into(), + ), + ) .unwrap(); - let hash3 = block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 3, - }), - )) + let hash3 = block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 3, + }) + .into(), + ), + ) .unwrap(); // when - pool.validated_pool.clear_stale(&BlockId::Number(5)).unwrap(); + pool.validated_pool.clear_stale(&api.expect_hash_and_number(5)); // then assert_eq!(pool.validated_pool().ready().count(), 0); @@ -646,21 +730,23 @@ mod tests { fn should_ban_mined_transactions() { // given let (pool, api) = pool(); - let hash1 = block_on(pool.submit_one( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + let hash1 = block_on( + pool.submit_one( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); // when - block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![0]], vec![hash1])) - .unwrap(); + block_on(pool.prune_tags(&api.expect_hash_and_number(1), vec![vec![0]], vec![hash1])); // then assert!(pool.validated_pool.is_banned(&hash1)); @@ -685,20 +771,24 @@ mod tests { let api = Arc::new(TestApi::default()); let pool = Pool::new(options, true.into(), api.clone()); - let hash1 = block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt)).unwrap(); + let hash1 = + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, xt.into())).unwrap(); assert_eq!(pool.validated_pool().status().future, 1); // when - let hash2 = block_on(pool.submit_one( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Bob.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 10, - }), - )) + let hash2 = block_on( + pool.submit_one( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Bob.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 10, + }) + .into(), + ), + ) .unwrap(); // then @@ -718,16 +808,19 @@ mod tests { let pool = Pool::new(options, true.into(), api.clone()); // when - block_on(pool.submit_one( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 1, - }), - )) + block_on( + pool.submit_one( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 1, + }) + .into(), + ), + ) .unwrap_err(); // then @@ -741,16 +834,19 @@ mod tests { let (pool, api) = pool(); // when - let err = block_on(pool.submit_one( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: INVALID_NONCE, - }), - )) + let err = block_on( + pool.submit_one( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: INVALID_NONCE, + }) + .into(), + ), + ) .unwrap_err(); // then @@ -766,96 +862,113 @@ mod tests { fn should_trigger_ready_and_finalized() { // given let (pool, api) = pool(); - let watcher = block_on(pool.submit_and_watch( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + let watcher = block_on( + pool.submit_and_watch( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(pool.validated_pool().status().future, 0); - let hash_of_block2 = api.expect_hash_from_number(2); + let han_of_block2 = api.expect_hash_and_number(2); // when - block_on(pool.prune_tags(hash_of_block2, vec![vec![0u8]], vec![])).unwrap(); + block_on(pool.prune_tags(&han_of_block2, vec![vec![0u8]], vec![])); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); // then let mut stream = futures::executor::block_on_stream(watcher.into_stream()); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock((hash_of_block2.into(), 0))),); + assert_eq!( + stream.next(), + Some(TransactionStatus::InBlock((han_of_block2.hash.into(), 0))), + ); } #[test] fn should_trigger_ready_and_finalized_when_pruning_via_hash() { // given let (pool, api) = pool(); - let watcher = block_on(pool.submit_and_watch( - api.expect_hash_from_number(0), - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + let watcher = block_on( + pool.submit_and_watch( + &api.expect_hash_and_number(0), + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(pool.validated_pool().status().future, 0); - let hash_of_block2 = api.expect_hash_from_number(2); + let han_of_block2 = api.expect_hash_and_number(2); // when - block_on(pool.prune_tags(hash_of_block2, vec![vec![0u8]], vec![*watcher.hash()])) - .unwrap(); + block_on(pool.prune_tags(&han_of_block2, vec![vec![0u8]], vec![*watcher.hash()])); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 0); // then let mut stream = futures::executor::block_on_stream(watcher.into_stream()); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock((hash_of_block2.into(), 0))),); + assert_eq!( + stream.next(), + Some(TransactionStatus::InBlock((han_of_block2.hash.into(), 0))), + ); } #[test] fn should_trigger_future_and_ready_after_promoted() { // given let (pool, api) = pool(); - let hash_of_block0 = api.expect_hash_from_number(0); - - let watcher = block_on(pool.submit_and_watch( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 1, - }), - )) + let han_of_block0 = api.expect_hash_and_number(0); + + let watcher = block_on( + pool.submit_and_watch( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 1, + }) + .into(), + ), + ) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 0); assert_eq!(pool.validated_pool().status().future, 1); // when - block_on(pool.submit_one( - hash_of_block0, - SOURCE, - uxt(Transfer { - from: Alice.into(), - to: AccountId::from_h256(H256::from_low_u64_be(2)), - amount: 5, - nonce: 0, - }), - )) + block_on( + pool.submit_one( + &han_of_block0, + SOURCE, + uxt(Transfer { + from: Alice.into(), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce: 0, + }) + .into(), + ), + ) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 2); @@ -876,7 +989,7 @@ mod tests { nonce: 0, }); let watcher = - block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt)) + block_on(pool.submit_and_watch(&api.expect_hash_and_number(0), SOURCE, uxt.into())) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); @@ -901,7 +1014,7 @@ mod tests { nonce: 0, }); let watcher = - block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, uxt)) + block_on(pool.submit_and_watch(&api.expect_hash_and_number(0), SOURCE, uxt.into())) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); @@ -934,7 +1047,7 @@ mod tests { nonce: 0, }); let watcher = - block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt)) + block_on(pool.submit_and_watch(&api.expect_hash_and_number(0), SOURCE, xt.into())) .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); @@ -945,7 +1058,7 @@ mod tests { amount: 4, nonce: 1, }); - block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(1), SOURCE, xt.into())).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // then @@ -968,7 +1081,8 @@ mod tests { // after validation `IncludeData` will have priority set to 9001 // (validate_transaction mock) let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build(); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, xt.into())) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // then @@ -980,7 +1094,8 @@ mod tests { amount: 4, nonce: 1, }); - let result = block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)); + let result = + block_on(pool.submit_one(&api.expect_hash_and_number(1), SOURCE, xt.into())); assert!(matches!( result, Err(sc_transaction_pool_api::error::Error::ImmediatelyDropped) @@ -995,12 +1110,12 @@ mod tests { let api = Arc::new(TestApi::default()); let pool = Pool::new(options, true.into(), api.clone()); - let hash_of_block0 = api.expect_hash_from_number(0); + let han_of_block0 = api.expect_hash_and_number(0); // after validation `IncludeData` will have priority set to 9001 // (validate_transaction mock) let xt = ExtrinsicBuilder::new_include_data(Vec::new()).build(); - block_on(pool.submit_and_watch(hash_of_block0, SOURCE, xt)).unwrap(); + block_on(pool.submit_and_watch(&han_of_block0, SOURCE, xt.into())).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // after validation `Transfer` will have priority set to 4 (validate_transaction @@ -1011,14 +1126,16 @@ mod tests { amount: 5, nonce: 0, }); - let watcher = block_on(pool.submit_and_watch(hash_of_block0, SOURCE, xt)).unwrap(); + let watcher = + block_on(pool.submit_and_watch(&han_of_block0, SOURCE, xt.into())).unwrap(); assert_eq!(pool.validated_pool().status().ready, 2); // when // after validation `Store` will have priority set to 9001 (validate_transaction // mock) let xt = ExtrinsicBuilder::new_indexed_call(Vec::new()).build(); - block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt)).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(1), SOURCE, xt.into())) + .unwrap(); assert_eq!(pool.validated_pool().status().ready, 2); // then @@ -1038,7 +1155,7 @@ mod tests { let api = Arc::new(api); let pool = Arc::new(Pool::new(Default::default(), true.into(), api.clone())); - let hash_of_block0 = api.expect_hash_from_number(0); + let han_of_block0 = api.expect_hash_and_number(0); // when let xt = uxt(Transfer { @@ -1050,9 +1167,12 @@ mod tests { // This transaction should go to future, since we use `nonce: 1` let pool2 = pool.clone(); - std::thread::spawn(move || { - block_on(pool2.submit_one(hash_of_block0, SOURCE, xt)).unwrap(); - ready.send(()).unwrap(); + std::thread::spawn({ + let hash_of_block0 = han_of_block0.clone(); + move || { + block_on(pool2.submit_one(&hash_of_block0, SOURCE, xt.into())).unwrap(); + ready.send(()).unwrap(); + } }); // But now before the previous one is imported we import @@ -1065,13 +1185,12 @@ mod tests { }); // The tag the above transaction provides (TestApi is using just nonce as u8) let provides = vec![0_u8]; - block_on(pool.submit_one(hash_of_block0, SOURCE, xt)).unwrap(); + block_on(pool.submit_one(&han_of_block0, SOURCE, xt.into())).unwrap(); assert_eq!(pool.validated_pool().status().ready, 1); // Now block import happens before the second transaction is able to finish // verification. - block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![provides], vec![])) - .unwrap(); + block_on(pool.prune_tags(&api.expect_hash_and_number(1), vec![provides], vec![])); assert_eq!(pool.validated_pool().status().ready, 0); // so when we release the verification of the previous one it will have diff --git a/substrate/client/transaction-pool/src/graph/ready.rs b/substrate/client/transaction-pool/src/graph/ready.rs index b4a5d9e3ba71..860bcff0bace 100644 --- a/substrate/client/transaction-pool/src/graph/ready.rs +++ b/substrate/client/transaction-pool/src/graph/ready.rs @@ -24,7 +24,7 @@ use std::{ }; use crate::LOG_TARGET; -use log::{debug, trace}; +use log::trace; use sc_transaction_pool_api::error; use serde::Serialize; use sp_runtime::{traits::Member, transaction_validity::TransactionTag as Tag}; @@ -84,7 +84,7 @@ pub struct ReadyTx { /// How many required tags are provided inherently /// /// Some transactions might be already pruned from the queue, - /// so when we compute ready set we may consider this transactions ready earlier. + /// so when we compute ready set we may consider these transactions ready earlier. pub requires_offset: usize, } @@ -106,7 +106,7 @@ qed "#; /// Validated transactions that are block ready with all their dependencies met. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct ReadyTransactions { /// Next free insertion id (used to indicate when a transaction was inserted into the pool). insertion_id: u64, @@ -521,9 +521,9 @@ impl BestIterator { /// When invoked on a fully drained iterator it has no effect either. pub fn report_invalid(&mut self, tx: &Arc>) { if let Some(to_report) = self.all.get(&tx.hash) { - debug!( + trace!( target: LOG_TARGET, - "[{:?}] Reported as invalid. Will skip sub-chains while iterating.", + "[{:?}] best-iterator: Reported as invalid. Will skip sub-chains while iterating.", to_report.transaction.transaction.hash ); for hash in &to_report.unlocks { @@ -544,7 +544,7 @@ impl Iterator for BestIterator { // Check if the transaction was marked invalid. if self.invalid.contains(hash) { - debug!( + trace!( target: LOG_TARGET, "[{:?}] Skipping invalid child transaction while iterating.", hash, ); @@ -703,7 +703,7 @@ mod tests { tx6.requires = vec![tx5.provides[0].clone()]; tx6.provides = vec![]; let tx7 = Transaction { - data: vec![7], + data: vec![7].into(), bytes: 1, hash: 7, priority: 1, diff --git a/substrate/client/transaction-pool/src/graph/tracked_map.rs b/substrate/client/transaction-pool/src/graph/tracked_map.rs index 44c2c738ab1b..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, @@ -46,6 +46,20 @@ impl Default for TrackedMap { } } +impl Clone for TrackedMap +where + K: Clone, + V: Clone, +{ + fn clone(&self) -> Self { + Self { + index: Arc::from(RwLock::from(self.index.read().clone())), + bytes: self.bytes.load(AtomicOrdering::Relaxed).into(), + length: self.length.load(AtomicOrdering::Relaxed).into(), + } + } +} + impl TrackedMap { /// Current tracked length of the content. pub fn len(&self) -> usize { @@ -87,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> { @@ -135,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 3d7cfeb46b04..d7f55198a40a 100644 --- a/substrate/client/transaction-pool/src/graph/validated_pool.rs +++ b/substrate/client/transaction-pool/src/graph/validated_pool.rs @@ -22,13 +22,13 @@ use std::{ sync::Arc, }; -use crate::LOG_TARGET; +use crate::{common::log_xt::log_xt_trace, LOG_TARGET}; use futures::channel::mpsc::{channel, Sender}; use parking_lot::{Mutex, RwLock}; use sc_transaction_pool_api::{error, PoolStatus, ReadyTransactions}; use serde::Serialize; +use sp_blockchain::HashAndNumber; use sp_runtime::{ - generic::BlockId, traits::{self, SaturatedConversion}, transaction_validity::{TransactionSource, TransactionTag as Tag, ValidTransaction}, }; @@ -86,17 +86,18 @@ pub type ValidatedTransactionFor = ValidatedTransaction, ExtrinsicFor, ::Error>; /// A closure that returns true if the local node is a validator that can author blocks. -pub struct IsValidator(Box bool + Send + Sync>); +#[derive(Clone)] +pub struct IsValidator(Arc bool + Send + Sync>>); impl From for IsValidator { fn from(is_validator: bool) -> Self { - Self(Box::new(move || is_validator)) + Self(Arc::new(Box::new(move || is_validator))) } } impl From bool + Send + Sync>> for IsValidator { fn from(is_validator: Box bool + Send + Sync>) -> Self { - Self(is_validator) + Self(Arc::new(is_validator)) } } @@ -111,6 +112,20 @@ pub struct ValidatedPool { rotator: PoolRotator>, } +impl Clone for ValidatedPool { + fn clone(&self) -> Self { + Self { + api: self.api.clone(), + is_validator: self.is_validator.clone(), + options: self.options.clone(), + listener: Default::default(), + pool: RwLock::from(self.pool.read().clone()), + import_notification_sinks: Default::default(), + rotator: PoolRotator::default(), + } + } +} + impl ValidatedPool { /// Create a new transaction pool. pub fn new(options: Options, is_validator: IsValidator, api: Arc) -> Self { @@ -187,6 +202,7 @@ impl ValidatedPool { fn submit_one(&self, tx: ValidatedTransactionFor) -> Result, B::Error> { match tx { ValidatedTransaction::Valid(tx) => { + log::trace!(target: LOG_TARGET, "[{:?}] ValidatedPool::submit_one", tx.hash); if !tx.propagate && !(self.is_validator.0)() { return Err(error::Error::Unactionable.into()) } @@ -216,10 +232,12 @@ impl ValidatedPool { Ok(*imported.hash()) }, ValidatedTransaction::Invalid(hash, err) => { + log::trace!(target: LOG_TARGET, "[{:?}] ValidatedPool::submit_one invalid: {:?}", hash, err); self.rotator.ban(&Instant::now(), std::iter::once(hash)); Err(err) }, ValidatedTransaction::Unknown(hash, err) => { + log::trace!(target: LOG_TARGET, "[{:?}] ValidatedPool::submit_one unknown {:?}", hash, err); self.listener.write().invalid(&hash); Err(err) }, @@ -231,7 +249,6 @@ impl ValidatedPool { let ready_limit = &self.options.ready; let future_limit = &self.options.future; - log::debug!(target: LOG_TARGET, "Pool Status: {:?}", status); if ready_limit.is_exceeded(status.ready, status.ready_bytes) || future_limit.is_exceeded(status.future, status.future_bytes) { @@ -257,13 +274,13 @@ impl ValidatedPool { removed }; if !removed.is_empty() { - log::debug!(target: LOG_TARGET, "Enforcing limits: {} dropped", removed.len()); + log::trace!(target: LOG_TARGET, "Enforcing limits: {} dropped", removed.len()); } // run notifications let mut listener = self.listener.write(); for h in &removed { - listener.dropped(h, None); + listener.dropped(h, None, true); } removed @@ -280,7 +297,7 @@ impl ValidatedPool { match tx { ValidatedTransaction::Valid(tx) => { let hash = self.api.hash_and_length(&tx.data).0; - let watcher = self.listener.write().create_watcher(hash); + let watcher = self.create_watcher(hash); self.submit(std::iter::once(ValidatedTransaction::Valid(tx))) .pop() .expect("One extrinsic passed; one result returned; qed") @@ -294,6 +311,19 @@ impl ValidatedPool { } } + /// Creates a new watcher for given extrinsic. + pub fn create_watcher( + &self, + tx_hash: ExtrinsicHash, + ) -> Watcher, ExtrinsicHash> { + self.listener.write().create_watcher(tx_hash) + } + + /// Provides a list of hashes for all watched transactions in the pool. + pub fn watched_transactions(&self) -> Vec> { + self.listener.read().watched_transactions().map(Clone::clone).collect() + } + /// Resubmits revalidated transactions back to the pool. /// /// Removes and then submits passed transactions and all dependent transactions. @@ -351,7 +381,7 @@ impl ValidatedPool { initial_statuses.insert(removed_hash, Status::Ready); txs_to_resubmit.push((removed_hash, tx_to_resubmit)); } - // make sure to remove the hash even if it's not present in the pool any more. + // make sure to remove the hash even if it's not present in the pool anymore. updated_transactions.remove(&hash); } @@ -423,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), + Status::Dropped => listener.dropped(&hash, None, false), Status::Failed => listener.invalid(&hash), } } @@ -451,7 +481,7 @@ impl ValidatedPool { pub fn prune_tags( &self, tags: impl IntoIterator, - ) -> Result, ExtrinsicFor>, B::Error> { + ) -> PruneStatus, ExtrinsicFor> { // Perform tag-based pruning in the base pool let status = self.pool.write().prune_tags(tags); // Notify event listeners of all transactions @@ -462,21 +492,21 @@ impl ValidatedPool { fire_events(&mut *listener, promoted); } for f in &status.failed { - listener.dropped(f, None); + listener.dropped(f, None, false); } } - Ok(status) + status } /// Resubmit transactions that have been revalidated after prune_tags call. pub fn resubmit_pruned( &self, - at: &BlockId, + at: &HashAndNumber, known_imported_hashes: impl IntoIterator> + Clone, pruned_hashes: Vec>, pruned_xts: Vec>, - ) -> Result<(), B::Error> { + ) { debug_assert_eq!(pruned_hashes.len(), pruned_xts.len()); // Resubmit pruned transactions @@ -493,35 +523,29 @@ impl ValidatedPool { // Fire `pruned` notifications for collected hashes and make sure to include // `known_imported_hashes` since they were just imported as part of the block. let hashes = hashes.chain(known_imported_hashes.into_iter()); - self.fire_pruned(at, hashes)?; + self.fire_pruned(at, hashes); // perform regular cleanup of old transactions in the pool // and update temporary bans. - self.clear_stale(at)?; - Ok(()) + self.clear_stale(at); } /// Fire notifications for pruned transactions. pub fn fire_pruned( &self, - at: &BlockId, + at: &HashAndNumber, hashes: impl Iterator>, - ) -> Result<(), B::Error> { - let header_hash = self - .api - .block_id_to_hash(at)? - .ok_or_else(|| error::Error::InvalidBlockId(format!("{:?}", at)))?; + ) { let mut listener = self.listener.write(); let mut set = HashSet::with_capacity(hashes.size_hint().0); for h in hashes { // `hashes` has possibly duplicate hashes. // we'd like to send out the `InBlock` notification only once. if !set.contains(&h) { - listener.pruned(header_hash, &h); + listener.pruned(at.hash, &h); set.insert(h); } } - Ok(()) } /// Removes stale transactions from the pool. @@ -529,16 +553,13 @@ impl ValidatedPool { /// Stale transactions are transaction beyond their longevity period. /// Note this function does not remove transactions that are already included in the chain. /// See `prune_tags` if you want this. - pub fn clear_stale(&self, at: &BlockId) -> Result<(), B::Error> { - let block_number = self - .api - .block_id_to_number(at)? - .ok_or_else(|| error::Error::InvalidBlockId(format!("{:?}", at)))? - .saturated_into::(); + pub fn clear_stale(&self, at: &HashAndNumber) { + let HashAndNumber { number, .. } = *at; + let number = number.saturated_into::(); let now = Instant::now(); let to_remove = { self.ready() - .filter(|tx| self.rotator.ban_if_stale(&now, block_number, tx)) + .filter(|tx| self.rotator.ban_if_stale(&now, number, tx)) .map(|tx| tx.hash) .collect::>() }; @@ -546,7 +567,7 @@ impl ValidatedPool { let p = self.pool.read(); let mut hashes = Vec::new(); for tx in p.futures() { - if self.rotator.ban_if_stale(&now, block_number, tx) { + if self.rotator.ban_if_stale(&now, number, tx) { hashes.push(tx.hash); } } @@ -557,8 +578,6 @@ impl ValidatedPool { self.remove_invalid(&futures_to_remove); // clear banned transactions timeouts self.rotator.clear_timeouts(&now); - - Ok(()) } /// Get api reference. @@ -598,14 +617,15 @@ impl ValidatedPool { return vec![] } - log::debug!(target: LOG_TARGET, "Removing invalid transactions: {:?}", hashes); + log::trace!(target: LOG_TARGET, "Removing invalid transactions: {:?}", hashes.len()); // temporarily ban invalid transactions self.rotator.ban(&Instant::now(), hashes.iter().cloned()); let invalid = self.pool.write().remove_subtree(hashes); - log::debug!(target: LOG_TARGET, "Removed invalid transactions: {:?}", invalid); + log::trace!(target: LOG_TARGET, "Removed invalid transactions: {:?}", invalid.len()); + log_xt_trace!(target: LOG_TARGET, invalid.iter().map(|t| t.hash), "{:?} Removed invalid transaction"); let mut listener = self.listener.write(); for tx in &invalid { @@ -645,6 +665,12 @@ impl ValidatedPool { pub fn on_block_retracted(&self, block_hash: BlockHash) { self.listener.write().retracted(block_hash) } + + pub fn create_dropped_by_limits_stream( + &self, + ) -> super::listener::DroppedByLimitsStream, BlockHash> { + self.listener.write().create_dropped_by_limits_stream() + } } fn fire_events(listener: &mut Listener, imported: &base::Imported) @@ -656,7 +682,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))); + removed.iter().for_each(|r| listener.dropped(&r.hash, Some(hash), false)); 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 fc440771d7bb..fb7cf99d4dc6 100644 --- a/substrate/client/transaction-pool/src/graph/watcher.rs +++ b/substrate/client/transaction-pool/src/graph/watcher.rs @@ -123,7 +123,7 @@ impl Sender { self.send(TransactionStatus::Broadcast(peers)) } - /// Returns true if the are no more listeners for this extrinsic or it was finalized. + /// Returns true if there are no more listeners for this extrinsic, or it was finalized. pub fn is_done(&self) -> bool { self.is_finalized || self.receivers.is_empty() } diff --git a/substrate/client/transaction-pool/src/lib.rs b/substrate/client/transaction-pool/src/lib.rs index 64b301e6bf36..3d3d596c291f 100644 --- a/substrate/client/transaction-pool/src/lib.rs +++ b/substrate/client/transaction-pool/src/lib.rs @@ -22,776 +22,36 @@ #![warn(missing_docs)] #![warn(unused_extern_crates)] -mod api; -mod enactment_state; -pub mod error; +mod builder; +mod common; +mod fork_aware_txpool; mod graph; -mod metrics; -mod revalidation; -#[cfg(test)] -mod tests; - -pub use crate::api::FullChainApi; -use async_trait::async_trait; -use enactment_state::{EnactmentAction, EnactmentState}; -use futures::{ - channel::oneshot, - future::{self, ready}, - prelude::*, -}; -pub use graph::{ - base_pool::Limit as PoolLimit, ChainApi, Options, Pool, Transaction, ValidatedTransaction, -}; -use parking_lot::Mutex; -use std::{ - collections::{HashMap, HashSet}, - pin::Pin, - sync::Arc, -}; - -use graph::{ExtrinsicHash, IsValidator}; -use sc_transaction_pool_api::{ - error::Error as TxPoolError, ChainEvent, ImportNotificationStream, MaintainedTransactionPool, - PoolFuture, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, TransactionSource, - TransactionStatusStreamFor, TxHash, -}; -use sp_core::traits::SpawnEssentialNamed; -use sp_runtime::{ - generic::BlockId, - traits::{AtLeast32Bit, Block as BlockT, Extrinsic, Header as HeaderT, NumberFor, Zero}, -}; -use std::time::Instant; - -use crate::metrics::MetricsLink as PrometheusMetrics; -use prometheus_endpoint::Registry as PrometheusRegistry; - -use sp_blockchain::{HashAndNumber, TreeRoute}; - -pub(crate) const LOG_TARGET: &str = "txpool"; - -type BoxedReadyIterator = - Box>> + Send>; +mod single_state_txpool; +mod transaction_pool_wrapper; + +use common::{api, enactment_state}; +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}; +use single_state_txpool::prune_known_txs_for_block; +pub use single_state_txpool::{BasicPool, RevalidationType}; +pub use transaction_pool_wrapper::TransactionPoolWrapper; + +type BoxedReadyIterator = Box< + dyn sc_transaction_pool_api::ReadyTransactions< + Item = Arc>, + > + Send, +>; type ReadyIteratorFor = BoxedReadyIterator, graph::ExtrinsicFor>; -type PolledIterator = Pin> + Send>>; - -/// A transaction pool for a full node. -pub type FullPool = BasicPool, Block>; - -/// Basic implementation of transaction pool that can be customized by providing PoolApi. -pub struct BasicPool -where - Block: BlockT, - PoolApi: graph::ChainApi, -{ - pool: Arc>, - api: Arc, - revalidation_strategy: Arc>>>, - revalidation_queue: Arc>, - ready_poll: Arc, Block>>>, - metrics: PrometheusMetrics, - enactment_state: Arc>>, -} - -struct ReadyPoll { - updated_at: NumberFor, - pollers: Vec<(NumberFor, oneshot::Sender)>, -} - -impl Default for ReadyPoll { - fn default() -> Self { - Self { updated_at: NumberFor::::zero(), pollers: Default::default() } - } -} - -impl ReadyPoll { - fn new(best_block_number: NumberFor) -> Self { - Self { updated_at: best_block_number, pollers: Default::default() } - } - - fn trigger(&mut self, number: NumberFor, iterator_factory: impl Fn() -> T) { - self.updated_at = number; - - let mut idx = 0; - while idx < self.pollers.len() { - if self.pollers[idx].0 <= number { - let poller_sender = self.pollers.swap_remove(idx); - log::debug!(target: LOG_TARGET, "Sending ready signal at block {}", number); - let _ = poller_sender.1.send(iterator_factory()); - } else { - idx += 1; - } - } - } - - fn add(&mut self, number: NumberFor) -> oneshot::Receiver { - let (sender, receiver) = oneshot::channel(); - self.pollers.push((number, sender)); - receiver - } - - fn updated_at(&self) -> NumberFor { - self.updated_at - } -} - -/// Type of revalidation. -pub enum RevalidationType { - /// Light revalidation type. - /// - /// During maintenance, transaction pool makes periodic revalidation - /// of all transactions depending on number of blocks or time passed. - /// Also this kind of revalidation does not resubmit transactions from - /// retracted blocks, since it is too expensive. - Light, - - /// Full revalidation type. - /// - /// During maintenance, transaction pool revalidates some fixed amount of - /// transactions from the pool of valid transactions. - Full, -} - -impl BasicPool -where - Block: BlockT, - PoolApi: graph::ChainApi + 'static, -{ - /// Create new basic transaction pool with provided api, for tests. - pub fn new_test( - pool_api: Arc, - best_block_hash: Block::Hash, - finalized_hash: Block::Hash, - options: graph::Options, - ) -> (Self, Pin + Send>>) { - let pool = Arc::new(graph::Pool::new(options, true.into(), pool_api.clone())); - let (revalidation_queue, background_task) = revalidation::RevalidationQueue::new_background( - pool_api.clone(), - pool.clone(), - finalized_hash, - ); - ( - Self { - api: pool_api, - pool, - revalidation_queue: Arc::new(revalidation_queue), - revalidation_strategy: Arc::new(Mutex::new(RevalidationStrategy::Always)), - ready_poll: Default::default(), - metrics: Default::default(), - enactment_state: Arc::new(Mutex::new(EnactmentState::new( - best_block_hash, - finalized_hash, - ))), - }, - background_task, - ) - } - - /// Create new basic transaction pool with provided api and custom - /// revalidation type. - pub fn with_revalidation_type( - options: graph::Options, - is_validator: IsValidator, - pool_api: Arc, - prometheus: Option<&PrometheusRegistry>, - revalidation_type: RevalidationType, - spawner: impl SpawnEssentialNamed, - best_block_number: NumberFor, - best_block_hash: Block::Hash, - finalized_hash: Block::Hash, - ) -> Self { - let pool = Arc::new(graph::Pool::new(options, is_validator, pool_api.clone())); - let (revalidation_queue, background_task) = match revalidation_type { - RevalidationType::Light => - (revalidation::RevalidationQueue::new(pool_api.clone(), pool.clone()), None), - RevalidationType::Full => { - let (queue, background) = revalidation::RevalidationQueue::new_background( - pool_api.clone(), - pool.clone(), - finalized_hash, - ); - (queue, Some(background)) - }, - }; - - if let Some(background_task) = background_task { - spawner.spawn_essential("txpool-background", Some("transaction-pool"), background_task); - } - - Self { - api: pool_api, - pool, - revalidation_queue: Arc::new(revalidation_queue), - revalidation_strategy: Arc::new(Mutex::new(match revalidation_type { - RevalidationType::Light => - RevalidationStrategy::Light(RevalidationStatus::NotScheduled), - RevalidationType::Full => RevalidationStrategy::Always, - })), - ready_poll: Arc::new(Mutex::new(ReadyPoll::new(best_block_number))), - metrics: PrometheusMetrics::new(prometheus), - enactment_state: Arc::new(Mutex::new(EnactmentState::new( - best_block_hash, - finalized_hash, - ))), - } - } - - /// Gets shared reference to the underlying pool. - pub fn pool(&self) -> &Arc> { - &self.pool - } - - /// Get access to the underlying api - pub fn api(&self) -> &PoolApi { - &self.api - } -} - -impl TransactionPool for BasicPool -where - Block: BlockT, - PoolApi: 'static + graph::ChainApi, -{ - type Block = PoolApi::Block; - type Hash = graph::ExtrinsicHash; - type InPoolTransaction = graph::base_pool::Transaction, TransactionFor>; - type Error = PoolApi::Error; - - fn submit_at( - &self, - at: ::Hash, - source: TransactionSource, - xts: Vec>, - ) -> PoolFuture, Self::Error>>, Self::Error> { - let pool = self.pool.clone(); - - self.metrics - .report(|metrics| metrics.submitted_transactions.inc_by(xts.len() as u64)); - - async move { pool.submit_at(at, source, xts).await }.boxed() - } - - fn submit_one( - &self, - at: ::Hash, - source: TransactionSource, - xt: TransactionFor, - ) -> PoolFuture, Self::Error> { - let pool = self.pool.clone(); - - self.metrics.report(|metrics| metrics.submitted_transactions.inc()); - - async move { pool.submit_one(at, source, xt).await }.boxed() - } - - fn submit_and_watch( - &self, - at: ::Hash, - source: TransactionSource, - xt: TransactionFor, - ) -> PoolFuture>>, Self::Error> { - let pool = self.pool.clone(); - - self.metrics.report(|metrics| metrics.submitted_transactions.inc()); - - async move { - let watcher = pool.submit_and_watch(at, source, xt).await?; - - Ok(watcher.into_stream().boxed()) - } - .boxed() - } - - fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { - let removed = self.pool.validated_pool().remove_invalid(hashes); - self.metrics - .report(|metrics| metrics.validations_invalid.inc_by(removed.len() as u64)); - removed - } - - fn status(&self) -> PoolStatus { - self.pool.validated_pool().status() - } - - fn import_notification_stream(&self) -> ImportNotificationStream> { - self.pool.validated_pool().import_notification_stream() - } - - fn hash_of(&self, xt: &TransactionFor) -> TxHash { - self.pool.hash_of(xt) - } - - fn on_broadcasted(&self, propagations: HashMap, Vec>) { - self.pool.validated_pool().on_broadcasted(propagations) - } - - fn ready_transaction(&self, hash: &TxHash) -> Option> { - self.pool.validated_pool().ready_by_hash(hash) - } - - fn ready_at(&self, at: NumberFor) -> PolledIterator { - let status = self.status(); - // If there are no transactions in the pool, it is fine to return early. - // - // 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() - } - - 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() - } - - self.ready_poll - .lock() - .add(at) - .map(|received| { - received.unwrap_or_else(|e| { - log::warn!("Error receiving pending set: {:?}", e); - Box::new(std::iter::empty()) - }) - }) - .boxed() - } - - fn ready(&self) -> ReadyIteratorFor { - Box::new(self.pool.validated_pool().ready()) - } - - fn futures(&self) -> Vec { - let pool = self.pool.validated_pool().pool.read(); - - pool.futures().cloned().collect::>() - } -} - -impl FullPool -where - Block: BlockT, - Client: sp_api::ProvideRuntimeApi - + sc_client_api::BlockBackend - + sc_client_api::blockchain::HeaderBackend - + sp_runtime::traits::BlockIdTo - + sc_client_api::ExecutorProvider - + sc_client_api::UsageProvider - + sp_blockchain::HeaderMetadata - + Send - + Sync - + 'static, - Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, -{ - /// Create new basic transaction pool for a full node with the provided api. - pub fn new_full( - options: graph::Options, - is_validator: IsValidator, - prometheus: Option<&PrometheusRegistry>, - spawner: impl SpawnEssentialNamed, - client: Arc, - ) -> Arc { - let pool_api = Arc::new(FullChainApi::new(client.clone(), prometheus, &spawner)); - let pool = Arc::new(Self::with_revalidation_type( - options, - is_validator, - pool_api, - prometheus, - RevalidationType::Full, - spawner, - client.usage_info().chain.best_number, - client.usage_info().chain.best_hash, - client.usage_info().chain.finalized_hash, - )); - - pool - } -} - -impl sc_transaction_pool_api::LocalTransactionPool - for BasicPool, Block> -where - Block: BlockT, - Client: sp_api::ProvideRuntimeApi - + sc_client_api::BlockBackend - + sc_client_api::blockchain::HeaderBackend - + sp_runtime::traits::BlockIdTo - + sp_blockchain::HeaderMetadata, - Client: Send + Sync + 'static, - Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, -{ - type Block = Block; - type Hash = graph::ExtrinsicHash>; - type Error = as graph::ChainApi>::Error; - - fn submit_local( - &self, - at: Block::Hash, - xt: sc_transaction_pool_api::LocalTransactionFor, - ) -> Result { - use sp_runtime::{ - traits::SaturatedConversion, transaction_validity::TransactionValidityError, - }; - - let validity = self - .api - .validate_transaction_blocking(at, TransactionSource::Local, xt.clone())? - .map_err(|e| { - Self::Error::Pool(match e { - TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i), - TransactionValidityError::Unknown(u) => TxPoolError::UnknownTransaction(u), - }) - })?; - - let (hash, bytes) = self.pool.validated_pool().api().hash_and_length(&xt); - let block_number = self - .api - .block_id_to_number(&BlockId::hash(at))? - .ok_or_else(|| error::Error::BlockIdConversion(format!("{:?}", at)))?; - - let validated = ValidatedTransaction::valid_at( - block_number.saturated_into::(), - hash, - TransactionSource::Local, - xt, - bytes, - validity, - ); - - self.pool.validated_pool().submit(vec![validated]).remove(0) - } -} - -#[cfg_attr(test, derive(Debug))] -enum RevalidationStatus { - /// The revalidation has never been completed. - NotScheduled, - /// The revalidation is scheduled. - Scheduled(Option, Option), - /// The revalidation is in progress. - InProgress, -} - -enum RevalidationStrategy { - Always, - Light(RevalidationStatus), -} - -struct RevalidationAction { - revalidate: bool, - resubmit: bool, -} - -impl RevalidationStrategy { - pub fn clear(&mut self) { - if let Self::Light(status) = self { - status.clear() - } - } - - pub fn next( - &mut self, - block: N, - revalidate_time_period: Option, - revalidate_block_period: Option, - ) -> RevalidationAction { - match self { - Self::Light(status) => RevalidationAction { - revalidate: status.next_required( - block, - revalidate_time_period, - revalidate_block_period, - ), - resubmit: false, - }, - Self::Always => RevalidationAction { revalidate: true, resubmit: true }, - } - } -} - -impl RevalidationStatus { - /// Called when revalidation is completed. - pub fn clear(&mut self) { - *self = Self::NotScheduled; - } - - /// Returns true if revalidation is required. - pub fn next_required( - &mut self, - block: N, - revalidate_time_period: Option, - revalidate_block_period: Option, - ) -> bool { - match *self { - Self::NotScheduled => { - *self = Self::Scheduled( - revalidate_time_period.map(|period| Instant::now() + period), - revalidate_block_period.map(|period| block + period), - ); - false - }, - Self::Scheduled(revalidate_at_time, revalidate_at_block) => { - let is_required = - revalidate_at_time.map(|at| Instant::now() >= at).unwrap_or(false) || - revalidate_at_block.map(|at| block >= at).unwrap_or(false); - if is_required { - *self = Self::InProgress; - } - is_required - }, - Self::InProgress => false, - } - } -} - -/// Prune the known txs for the given block. -async fn prune_known_txs_for_block>( - block_hash: Block::Hash, - api: &Api, - pool: &graph::Pool, -) -> Vec> { - let extrinsics = api - .block_body(block_hash) - .await - .unwrap_or_else(|e| { - log::warn!("Prune known transactions: error request: {}", e); - None - }) - .unwrap_or_default(); - - let hashes = extrinsics.iter().map(|tx| pool.hash_of(tx)).collect::>(); - - log::trace!(target: LOG_TARGET, "Pruning transactions: {:?}", hashes); - - let header = match api.block_header(block_hash) { - Ok(Some(h)) => h, - Ok(None) => { - log::debug!(target: LOG_TARGET, "Could not find header for {:?}.", block_hash); - return hashes - }, - Err(e) => { - log::debug!(target: LOG_TARGET, "Error retrieving header for {:?}: {}", block_hash, e); - return hashes - }, - }; - - if let Err(e) = pool.prune(block_hash, *header.parent_hash(), &extrinsics).await { - log::error!("Cannot prune known in the pool: {}", e); - } - - hashes -} - -impl BasicPool -where - Block: BlockT, - PoolApi: 'static + graph::ChainApi, -{ - /// Handles enactment and retraction of blocks, prunes stale transactions - /// (that have already been enacted) and resubmits transactions that were - /// retracted. - async fn handle_enactment(&self, tree_route: TreeRoute) { - log::trace!(target: LOG_TARGET, "handle_enactment tree_route: {tree_route:?}"); - let pool = self.pool.clone(); - let api = self.api.clone(); - - let (hash, block_number) = match tree_route.last() { - Some(HashAndNumber { hash, number }) => (hash, number), - None => { - log::warn!( - target: LOG_TARGET, - "Skipping ChainEvent - no last block in tree route {:?}", - tree_route, - ); - return - }, - }; - - let next_action = self.revalidation_strategy.lock().next( - *block_number, - Some(std::time::Duration::from_secs(60)), - Some(20u32.into()), - ); - - // We keep track of everything we prune so that later we won't add - // transactions with those hashes from the retracted blocks. - let mut pruned_log = HashSet::>::new(); - - // If there is a tree route, we use this to prune known tx based on the enacted - // blocks. Before pruning enacted transactions, we inform the listeners about - // retracted blocks and their transactions. This order is important, because - // if we enact and retract the same transaction at the same time, we want to - // send first the retract and than the prune event. - for retracted in tree_route.retracted() { - // notify txs awaiting finality that it has been retracted - pool.validated_pool().on_block_retracted(retracted.hash); - } - - future::join_all( - tree_route - .enacted() - .iter() - .map(|h| prune_known_txs_for_block(h.hash, &*api, &*pool)), - ) - .await - .into_iter() - .for_each(|enacted_log| { - pruned_log.extend(enacted_log); - }); - - self.metrics - .report(|metrics| metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64)); - - if next_action.resubmit { - let mut resubmit_transactions = Vec::new(); - - for retracted in tree_route.retracted() { - let hash = retracted.hash; - - let block_transactions = api - .block_body(hash) - .await - .unwrap_or_else(|e| { - log::warn!("Failed to fetch block body: {}", e); - None - }) - .unwrap_or_default() - .into_iter() - .filter(|tx| tx.is_signed().unwrap_or(true)); - - let mut resubmitted_to_report = 0; - - resubmit_transactions.extend(block_transactions.into_iter().filter(|tx| { - let tx_hash = pool.hash_of(tx); - let contains = pruned_log.contains(&tx_hash); - - // need to count all transactions, not just filtered, here - resubmitted_to_report += 1; - - if !contains { - log::debug!( - target: LOG_TARGET, - "[{:?}]: Resubmitting from retracted block {:?}", - tx_hash, - hash, - ); - } - !contains - })); - - self.metrics.report(|metrics| { - metrics.block_transactions_resubmitted.inc_by(resubmitted_to_report) - }); - } - - if let Err(e) = pool - .resubmit_at( - *hash, - // These transactions are coming from retracted blocks, we should - // simply consider them external. - TransactionSource::External, - resubmit_transactions, - ) - .await - { - log::debug!( - target: LOG_TARGET, - "[{:?}] Error re-submitting transactions: {}", - hash, - e, - ) - } - } - - let extra_pool = pool.clone(); - // After #5200 lands, this arguably might be moved to the - // handler of "all blocks notification". - self.ready_poll - .lock() - .trigger(*block_number, move || Box::new(extra_pool.validated_pool().ready())); - - if next_action.revalidate { - let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); - self.revalidation_queue.revalidate_later(*hash, hashes).await; - - self.revalidation_strategy.lock().clear(); - } - } -} - -#[async_trait] -impl MaintainedTransactionPool for BasicPool -where - Block: BlockT, - PoolApi: 'static + graph::ChainApi, -{ - async fn maintain(&self, event: ChainEvent) { - let prev_finalized_block = self.enactment_state.lock().recent_finalized_block(); - let compute_tree_route = |from, to| -> Result, String> { - match self.api.tree_route(from, to) { - Ok(tree_route) => Ok(tree_route), - Err(e) => - return Err(format!( - "Error occurred while computing tree_route from {from:?} to {to:?}: {e}" - )), - } - }; - let block_id_to_number = - |hash| self.api.block_id_to_number(&BlockId::Hash(hash)).map_err(|e| format!("{}", e)); - - let result = - self.enactment_state - .lock() - .update(&event, &compute_tree_route, &block_id_to_number); - - match result { - Err(msg) => { - log::debug!(target: LOG_TARGET, "{msg}"); - self.enactment_state.lock().force_update(&event); - }, - Ok(EnactmentAction::Skip) => return, - Ok(EnactmentAction::HandleFinalization) => {}, - Ok(EnactmentAction::HandleEnactment(tree_route)) => { - self.handle_enactment(tree_route).await; - }, - }; - - if let ChainEvent::Finalized { hash, tree_route } = event { - log::trace!( - target: LOG_TARGET, - "on-finalized enacted: {tree_route:?}, previously finalized: \ - {prev_finalized_block:?}", - ); - - for hash in tree_route.iter().chain(std::iter::once(&hash)) { - if let Err(e) = self.pool.validated_pool().on_block_finalized(*hash).await { - log::warn!( - target: LOG_TARGET, - "Error occurred while attempting to notify watchers about finalization {}: {}", - hash, e - ) - } - } - } - } -} - -/// Inform the transaction pool about imported and finalized blocks. -pub async fn notification_future(client: Arc, txpool: Arc) -where - Block: BlockT, - Client: sc_client_api::BlockchainEvents, - Pool: MaintainedTransactionPool, -{ - let import_stream = client - .import_notification_stream() - .filter_map(|n| ready(n.try_into().ok())) - .fuse(); - let finality_stream = client.finality_notification_stream().map(Into::into).fuse(); - - futures::stream::select(import_stream, finality_stream) - .for_each(|evt| txpool.maintain(evt)) - .await -} +/// Log target for transaction pool. +/// +/// It can be used by other components for logging functionality strictly related to txpool (e.g. +/// importing transaction). +pub const LOG_TARGET: &str = "txpool"; diff --git a/substrate/client/transaction-pool/src/single_state_txpool/metrics.rs b/substrate/client/transaction-pool/src/single_state_txpool/metrics.rs new file mode 100644 index 000000000000..28a0f66e7edc --- /dev/null +++ b/substrate/client/transaction-pool/src/single_state_txpool/metrics.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Transaction pool Prometheus metrics for single-state transaction pool. + +use crate::common::metrics::{GenericMetricsLink, MetricsRegistrant}; +use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; + +pub type MetricsLink = GenericMetricsLink; + +/// Transaction pool Prometheus metrics. +pub struct Metrics { + pub submitted_transactions: Counter, + pub validations_invalid: Counter, + pub block_transactions_pruned: Counter, + pub block_transactions_resubmitted: Counter, +} + +impl MetricsRegistrant for Metrics { + fn register(registry: &Registry) -> Result, PrometheusError> { + Ok(Box::from(Self { + submitted_transactions: register( + Counter::new( + "substrate_sub_txpool_submitted_transactions", + "Total number of transactions submitted", + )?, + registry, + )?, + validations_invalid: register( + Counter::new( + "substrate_sub_txpool_validations_invalid", + "Total number of transactions that were removed from the pool as invalid", + )?, + registry, + )?, + block_transactions_pruned: register( + Counter::new( + "substrate_sub_txpool_block_transactions_pruned", + "Total number of transactions that was requested to be pruned by block events", + )?, + registry, + )?, + block_transactions_resubmitted: register( + Counter::new( + "substrate_sub_txpool_block_transactions_resubmitted", + "Total number of transactions that was requested to be resubmitted by block events", + )?, + registry, + )?, + })) + } +} diff --git a/substrate/client/transaction-pool/src/single_state_txpool/mod.rs b/substrate/client/transaction-pool/src/single_state_txpool/mod.rs new file mode 100644 index 000000000000..d7ebb8c01cec --- /dev/null +++ b/substrate/client/transaction-pool/src/single_state_txpool/mod.rs @@ -0,0 +1,26 @@ +// 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 . + +//! Substrate single state transaction pool implementation. + +mod metrics; +mod revalidation; +pub(crate) mod single_state_txpool; + +pub(crate) use single_state_txpool::prune_known_txs_for_block; +pub use single_state_txpool::{BasicPool, RevalidationType}; diff --git a/substrate/client/transaction-pool/src/revalidation.rs b/substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs similarity index 91% rename from substrate/client/transaction-pool/src/revalidation.rs rename to substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs index 488ab19d8eab..5ef726c9f7d3 100644 --- a/substrate/client/transaction-pool/src/revalidation.rs +++ b/substrate/client/transaction-pool/src/single_state_txpool/revalidation.rs @@ -24,10 +24,7 @@ use std::{ sync::Arc, }; -use crate::{ - graph::{BlockHash, ChainApi, ExtrinsicHash, Pool, ValidatedTransaction}, - LOG_TARGET, -}; +use crate::graph::{BlockHash, ChainApi, ExtrinsicHash, Pool, ValidatedTransaction}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::{ generic::BlockId, traits::SaturatedConversion, transaction_validity::TransactionValidityError, @@ -40,6 +37,8 @@ const BACKGROUND_REVALIDATION_INTERVAL: Duration = Duration::from_millis(200); const MIN_BACKGROUND_REVALIDATION_BATCH_SIZE: usize = 20; +const LOG_TARGET: &str = "txpool::revalidation"; + /// Payload from queue to worker. struct WorkerPayload { at: BlockHash, @@ -75,11 +74,11 @@ async fn batch_revalidate( let block_number = match api.block_id_to_number(&BlockId::Hash(at)) { Ok(Some(n)) => n, Ok(None) => { - log::debug!(target: LOG_TARGET, "revalidation skipped at block {at:?}, could not get block number."); + log::trace!(target: LOG_TARGET, "revalidation skipped at block {at:?}, could not get block number."); return }, Err(e) => { - log::debug!(target: LOG_TARGET, "revalidation skipped at block {at:?}: {e:?}."); + log::trace!(target: LOG_TARGET, "revalidation skipped at block {at:?}: {e:?}."); return }, }; @@ -98,7 +97,7 @@ async fn batch_revalidate( for (validation_result, ext_hash, ext) in validation_results { match validation_result { Ok(Err(TransactionValidityError::Invalid(err))) => { - log::debug!( + log::trace!( target: LOG_TARGET, "[{:?}]: Revalidation: invalid {:?}", ext_hash, @@ -130,7 +129,7 @@ async fn batch_revalidate( ); }, Err(validation_err) => { - log::debug!( + log::trace!( target: LOG_TARGET, "[{:?}]: Removing due to error during revalidation: {}", ext_hash, @@ -256,7 +255,7 @@ impl RevalidationWorker { batch_revalidate(this.pool.clone(), this.api.clone(), this.best_block, next_batch).await; if batch_len > 0 || this.len() > 0 { - log::debug!( + log::trace!( target: LOG_TARGET, "Revalidated {} transactions. Left in the queue for revalidation: {}.", batch_len, @@ -273,7 +272,7 @@ impl RevalidationWorker { this.push(worker_payload); if this.members.len() > 0 { - log::debug!( + log::trace!( target: LOG_TARGET, "Updated revalidation queue at {:?}. Transactions: {:?}", this.best_block, @@ -359,6 +358,10 @@ where log::warn!(target: LOG_TARGET, "Failed to update background worker: {:?}", e); } } else { + log::debug!( + target: LOG_TARGET, + "batch_revalidate direct call" + ); let pool = self.pool.clone(); let api = self.api.clone(); batch_revalidate(pool, api, at, transactions).await @@ -370,8 +373,8 @@ where mod tests { use super::*; use crate::{ + common::tests::{uxt, TestApi}, graph::Pool, - tests::{uxt, TestApi}, }; use futures::executor::block_on; use sc_transaction_pool_api::TransactionSource; @@ -391,13 +394,16 @@ mod tests { nonce: 0, }); - let hash_of_block0 = api.expect_hash_from_number(0); + let han_of_block0 = api.expect_hash_and_number(0); - let uxt_hash = - block_on(pool.submit_one(hash_of_block0, TransactionSource::External, uxt.clone())) - .expect("Should be valid"); + let uxt_hash = block_on(pool.submit_one( + &han_of_block0, + TransactionSource::External, + uxt.clone().into(), + )) + .expect("Should be valid"); - block_on(queue.revalidate_later(hash_of_block0, vec![uxt_hash])); + block_on(queue.revalidate_later(han_of_block0.hash, vec![uxt_hash])); // revalidated in sync offload 2nd time assert_eq!(api.validation_requests().len(), 2); @@ -424,21 +430,23 @@ mod tests { nonce: 1, }); - let hash_of_block0 = api.expect_hash_from_number(0); + 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(hash_of_block0, TransactionSource::External, vec![uxt0, uxt1])) - .expect("Should be valid") - .into_iter() - .map(|r| r.expect("Should be valid")) - .collect::>(); + 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::>(); assert_eq!(api.validation_requests().len(), 2); assert_eq!(pool.validated_pool().status().ready, 2); // revalidation works fine for block 0: - block_on(queue.revalidate_later(hash_of_block0, uxt_hashes.clone())); + block_on(queue.revalidate_later(han_of_block0.hash, uxt_hashes.clone())); assert_eq!(api.validation_requests().len(), 4); 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 new file mode 100644 index 000000000000..b29630b563bb --- /dev/null +++ b/substrate/client/transaction-pool/src/single_state_txpool/single_state_txpool.rs @@ -0,0 +1,770 @@ +// 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 . + +//! Substrate transaction pool implementation. + +use super::{metrics::MetricsLink as PrometheusMetrics, revalidation}; +pub use crate::{ + api::FullChainApi, + graph::{ChainApi, ValidatedTransaction}, +}; +use crate::{ + common::{ + enactment_state::{EnactmentAction, EnactmentState}, + error, + log_xt::log_xt_trace, + }, + graph::{self, ExtrinsicHash, IsValidator}, + ReadyIteratorFor, LOG_TARGET, +}; +use async_trait::async_trait; +use futures::{channel::oneshot, future, prelude::*, Future, FutureExt}; +use parking_lot::Mutex; +use prometheus_endpoint::Registry as PrometheusRegistry; +use sc_transaction_pool_api::{ + error::Error as TxPoolError, ChainEvent, ImportNotificationStream, MaintainedTransactionPool, + PoolStatus, TransactionFor, TransactionPool, TransactionSource, TransactionStatusStreamFor, + TxHash, +}; +use sp_blockchain::{HashAndNumber, TreeRoute}; +use sp_core::traits::SpawnEssentialNamed; +use sp_runtime::{ + generic::BlockId, + traits::{AtLeast32Bit, Block as BlockT, Header as HeaderT, NumberFor, Zero}, +}; +use std::{ + collections::{HashMap, HashSet}, + pin::Pin, + sync::Arc, + time::Instant, +}; +use tokio::select; + +/// Basic implementation of transaction pool that can be customized by providing PoolApi. +pub struct BasicPool +where + Block: BlockT, + PoolApi: graph::ChainApi, +{ + pool: Arc>, + api: Arc, + revalidation_strategy: Arc>>>, + revalidation_queue: Arc>, + ready_poll: Arc, Block>>>, + metrics: PrometheusMetrics, + enactment_state: Arc>>, +} + +struct ReadyPoll { + updated_at: NumberFor, + pollers: Vec<(NumberFor, oneshot::Sender)>, +} + +impl Default for ReadyPoll { + fn default() -> Self { + Self { updated_at: NumberFor::::zero(), pollers: Default::default() } + } +} + +impl ReadyPoll { + fn new(best_block_number: NumberFor) -> Self { + Self { updated_at: best_block_number, pollers: Default::default() } + } + + fn trigger(&mut self, number: NumberFor, iterator_factory: impl Fn() -> T) { + self.updated_at = number; + + let mut idx = 0; + while idx < self.pollers.len() { + if self.pollers[idx].0 <= number { + let poller_sender = self.pollers.swap_remove(idx); + log::trace!(target: LOG_TARGET, "Sending ready signal at block {}", number); + let _ = poller_sender.1.send(iterator_factory()); + } else { + idx += 1; + } + } + } + + fn add(&mut self, number: NumberFor) -> oneshot::Receiver { + let (sender, receiver) = oneshot::channel(); + self.pollers.push((number, sender)); + receiver + } + + fn updated_at(&self) -> NumberFor { + self.updated_at + } +} + +/// Type of revalidation. +pub enum RevalidationType { + /// Light revalidation type. + /// + /// During maintenance, transaction pool makes periodic revalidation + /// of all transactions depending on number of blocks or time passed. + /// Also this kind of revalidation does not resubmit transactions from + /// retracted blocks, since it is too expensive. + Light, + + /// Full revalidation type. + /// + /// During maintenance, transaction pool revalidates some fixed amount of + /// transactions from the pool of valid transactions. + Full, +} + +impl BasicPool +where + Block: BlockT, + PoolApi: graph::ChainApi + 'static, +{ + /// Create new basic transaction pool with provided api, for tests. + pub fn new_test( + pool_api: Arc, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + options: graph::Options, + ) -> (Self, Pin + Send>>) { + let pool = Arc::new(graph::Pool::new(options, true.into(), pool_api.clone())); + let (revalidation_queue, background_task) = revalidation::RevalidationQueue::new_background( + pool_api.clone(), + pool.clone(), + finalized_hash, + ); + ( + Self { + api: pool_api, + pool, + revalidation_queue: Arc::new(revalidation_queue), + revalidation_strategy: Arc::new(Mutex::new(RevalidationStrategy::Always)), + ready_poll: Default::default(), + metrics: Default::default(), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), + }, + background_task, + ) + } + + /// Create new basic transaction pool with provided api and custom + /// revalidation type. + pub fn with_revalidation_type( + options: graph::Options, + is_validator: IsValidator, + pool_api: Arc, + prometheus: Option<&PrometheusRegistry>, + revalidation_type: RevalidationType, + spawner: impl SpawnEssentialNamed, + best_block_number: NumberFor, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + ) -> Self { + let pool = Arc::new(graph::Pool::new(options, is_validator, pool_api.clone())); + let (revalidation_queue, background_task) = match revalidation_type { + RevalidationType::Light => + (revalidation::RevalidationQueue::new(pool_api.clone(), pool.clone()), None), + RevalidationType::Full => { + let (queue, background) = revalidation::RevalidationQueue::new_background( + pool_api.clone(), + pool.clone(), + finalized_hash, + ); + (queue, Some(background)) + }, + }; + + if let Some(background_task) = background_task { + spawner.spawn_essential("txpool-background", Some("transaction-pool"), background_task); + } + + Self { + api: pool_api, + pool, + revalidation_queue: Arc::new(revalidation_queue), + revalidation_strategy: Arc::new(Mutex::new(match revalidation_type { + RevalidationType::Light => + RevalidationStrategy::Light(RevalidationStatus::NotScheduled), + RevalidationType::Full => RevalidationStrategy::Always, + })), + ready_poll: Arc::new(Mutex::new(ReadyPoll::new(best_block_number))), + metrics: PrometheusMetrics::new(prometheus), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), + } + } + + /// Gets shared reference to the underlying pool. + pub fn pool(&self) -> &Arc> { + &self.pool + } + + /// Get access to the underlying api + pub fn api(&self) -> &PoolApi { + &self.api + } + + async fn ready_at_with_timeout_internal( + &self, + at: Block::Hash, + timeout: std::time::Duration, + ) -> ReadyIteratorFor { + select! { + ready = self.ready_at(at)=> ready, + _ = futures_timer::Delay::new(timeout)=> self.ready() + } + } +} + +#[async_trait] +impl TransactionPool for BasicPool +where + Block: BlockT, + PoolApi: 'static + graph::ChainApi, +{ + type Block = PoolApi::Block; + type Hash = graph::ExtrinsicHash; + type InPoolTransaction = + graph::base_pool::Transaction, graph::ExtrinsicFor>; + type Error = PoolApi::Error; + + async fn submit_at( + &self, + at: ::Hash, + source: TransactionSource, + xts: Vec>, + ) -> Result, Self::Error>>, Self::Error> { + let pool = self.pool.clone(); + let xts = xts.into_iter().map(Arc::from).collect::>(); + + self.metrics + .report(|metrics| metrics.submitted_transactions.inc_by(xts.len() as u64)); + + let number = self.api.resolve_block_number(at); + let at = HashAndNumber { hash: at, number: number? }; + Ok(pool.submit_at(&at, source, xts).await) + } + + async fn submit_one( + &self, + at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> 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); + let at = HashAndNumber { hash: at, number: number? }; + pool.submit_one(&at, source, xt).await + } + + async fn submit_and_watch( + &self, + at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> 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); + + let at = HashAndNumber { hash: at, number: number? }; + let watcher = pool.submit_and_watch(&at, source, xt).await?; + + Ok(watcher.into_stream().boxed()) + } + + fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { + let removed = self.pool.validated_pool().remove_invalid(hashes); + self.metrics + .report(|metrics| metrics.validations_invalid.inc_by(removed.len() as u64)); + removed + } + + fn status(&self) -> PoolStatus { + self.pool.validated_pool().status() + } + + fn import_notification_stream(&self) -> ImportNotificationStream> { + self.pool.validated_pool().import_notification_stream() + } + + fn hash_of(&self, xt: &TransactionFor) -> TxHash { + self.pool.hash_of(xt) + } + + fn on_broadcasted(&self, propagations: HashMap, Vec>) { + self.pool.validated_pool().on_broadcasted(propagations) + } + + fn ready_transaction(&self, hash: &TxHash) -> Option> { + self.pool.validated_pool().ready_by_hash(hash) + } + + async fn ready_at(&self, at: ::Hash) -> ReadyIteratorFor { + let Ok(at) = self.api.resolve_block_number(at) else { + return Box::new(std::iter::empty()) as Box<_> + }; + + let status = self.status(); + // If there are no transactions in the pool, it is fine to return early. + // + // 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 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 iterator + } + + 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()) + }) + }); + + result.await + } + + fn ready(&self) -> ReadyIteratorFor { + Box::new(self.pool.validated_pool().ready()) + } + + fn futures(&self) -> Vec { + let pool = self.pool.validated_pool().pool.read(); + pool.futures().cloned().collect::>() + } + + async fn ready_at_with_timeout( + &self, + at: ::Hash, + timeout: std::time::Duration, + ) -> ReadyIteratorFor { + self.ready_at_with_timeout_internal(at, timeout).await + } +} + +impl BasicPool, Block> +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sc_client_api::ExecutorProvider + + sc_client_api::UsageProvider + + sp_blockchain::HeaderMetadata + + Send + + Sync + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + /// Create new basic transaction pool for a full node with the provided api. + pub fn new_full( + options: graph::Options, + is_validator: IsValidator, + prometheus: Option<&PrometheusRegistry>, + spawner: impl SpawnEssentialNamed, + client: Arc, + ) -> Self { + let pool_api = Arc::new(FullChainApi::new(client.clone(), prometheus, &spawner)); + let pool = Self::with_revalidation_type( + options, + is_validator, + pool_api, + prometheus, + RevalidationType::Full, + spawner, + client.usage_info().chain.best_number, + client.usage_info().chain.best_hash, + client.usage_info().chain.finalized_hash, + ); + + pool + } +} + +impl sc_transaction_pool_api::LocalTransactionPool + for BasicPool, Block> +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata, + Client: Send + Sync + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + type Block = Block; + type Hash = graph::ExtrinsicHash>; + type Error = as graph::ChainApi>::Error; + + fn submit_local( + &self, + at: Block::Hash, + xt: sc_transaction_pool_api::LocalTransactionFor, + ) -> Result { + use sp_runtime::{ + traits::SaturatedConversion, transaction_validity::TransactionValidityError, + }; + + let validity = self + .api + .validate_transaction_blocking(at, TransactionSource::Local, Arc::from(xt.clone()))? + .map_err(|e| { + Self::Error::Pool(match e { + TransactionValidityError::Invalid(i) => TxPoolError::InvalidTransaction(i), + TransactionValidityError::Unknown(u) => TxPoolError::UnknownTransaction(u), + }) + })?; + + let (hash, bytes) = self.pool.validated_pool().api().hash_and_length(&xt); + let block_number = self + .api + .block_id_to_number(&BlockId::hash(at))? + .ok_or_else(|| error::Error::BlockIdConversion(format!("{:?}", at)))?; + + let validated = ValidatedTransaction::valid_at( + block_number.saturated_into::(), + hash, + TransactionSource::Local, + Arc::from(xt), + bytes, + validity, + ); + + self.pool.validated_pool().submit(vec![validated]).remove(0) + } +} + +#[cfg_attr(test, derive(Debug))] +enum RevalidationStatus { + /// The revalidation has never been completed. + NotScheduled, + /// The revalidation is scheduled. + Scheduled(Option, Option), + /// The revalidation is in progress. + InProgress, +} + +enum RevalidationStrategy { + Always, + Light(RevalidationStatus), +} + +struct RevalidationAction { + revalidate: bool, + resubmit: bool, +} + +impl RevalidationStrategy { + pub fn clear(&mut self) { + if let Self::Light(status) = self { + status.clear() + } + } + + pub fn next( + &mut self, + block: N, + revalidate_time_period: Option, + revalidate_block_period: Option, + ) -> RevalidationAction { + match self { + Self::Light(status) => RevalidationAction { + revalidate: status.next_required( + block, + revalidate_time_period, + revalidate_block_period, + ), + resubmit: false, + }, + Self::Always => RevalidationAction { revalidate: true, resubmit: true }, + } + } +} + +impl RevalidationStatus { + /// Called when revalidation is completed. + pub fn clear(&mut self) { + *self = Self::NotScheduled; + } + + /// Returns true if revalidation is required. + pub fn next_required( + &mut self, + block: N, + revalidate_time_period: Option, + revalidate_block_period: Option, + ) -> bool { + match *self { + Self::NotScheduled => { + *self = Self::Scheduled( + revalidate_time_period.map(|period| Instant::now() + period), + revalidate_block_period.map(|period| block + period), + ); + false + }, + Self::Scheduled(revalidate_at_time, revalidate_at_block) => { + let is_required = + revalidate_at_time.map(|at| Instant::now() >= at).unwrap_or(false) || + revalidate_at_block.map(|at| block >= at).unwrap_or(false); + if is_required { + *self = Self::InProgress; + } + is_required + }, + Self::InProgress => false, + } + } +} + +/// Prune the known txs for the given block. +pub async fn prune_known_txs_for_block>( + at: &HashAndNumber, + api: &Api, + pool: &graph::Pool, +) -> Vec> { + let extrinsics = api + .block_body(at.hash) + .await + .unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Prune known transactions: error request: {}", e); + None + }) + .unwrap_or_default(); + + let hashes = extrinsics.iter().map(|tx| pool.hash_of(tx)).collect::>(); + + let header = match api.block_header(at.hash) { + Ok(Some(h)) => h, + Ok(None) => { + log::trace!(target: LOG_TARGET, "Could not find header for {:?}.", at.hash); + return hashes + }, + Err(e) => { + log::trace!(target: LOG_TARGET, "Error retrieving header for {:?}: {}", at.hash, e); + return hashes + }, + }; + + log_xt_trace!(target: LOG_TARGET, &hashes, "[{:?}] Pruning transaction."); + + pool.prune(at, *header.parent_hash(), &extrinsics).await; + hashes +} + +impl BasicPool +where + Block: BlockT, + PoolApi: 'static + graph::ChainApi, +{ + /// Handles enactment and retraction of blocks, prunes stale transactions + /// (that have already been enacted) and resubmits transactions that were + /// retracted. + async fn handle_enactment(&self, tree_route: TreeRoute) { + log::trace!(target: LOG_TARGET, "handle_enactment tree_route: {tree_route:?}"); + let pool = self.pool.clone(); + let api = self.api.clone(); + + let hash_and_number = match tree_route.last() { + Some(hash_and_number) => hash_and_number, + None => { + log::warn!( + target: LOG_TARGET, + "Skipping ChainEvent - no last block in tree route {:?}", + tree_route, + ); + return + }, + }; + + let next_action = self.revalidation_strategy.lock().next( + hash_and_number.number, + Some(std::time::Duration::from_secs(60)), + Some(20u32.into()), + ); + + // We keep track of everything we prune so that later we won't add + // transactions with those hashes from the retracted blocks. + let mut pruned_log = HashSet::>::new(); + + // If there is a tree route, we use this to prune known tx based on the enacted + // blocks. Before pruning enacted transactions, we inform the listeners about + // retracted blocks and their transactions. This order is important, because + // if we enact and retract the same transaction at the same time, we want to + // send first the retract and then the prune event. + for retracted in tree_route.retracted() { + // notify txs awaiting finality that it has been retracted + pool.validated_pool().on_block_retracted(retracted.hash); + } + + future::join_all( + tree_route.enacted().iter().map(|h| prune_known_txs_for_block(h, &*api, &*pool)), + ) + .await + .into_iter() + .for_each(|enacted_log| { + pruned_log.extend(enacted_log); + }); + + self.metrics + .report(|metrics| metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64)); + + if next_action.resubmit { + let mut resubmit_transactions = Vec::new(); + + for retracted in tree_route.retracted() { + let hash = retracted.hash; + + let block_transactions = api + .block_body(hash) + .await + .unwrap_or_else(|e| { + log::warn!(target: LOG_TARGET, "Failed to fetch block body: {}", e); + None + }) + .unwrap_or_default() + .into_iter(); + + let mut resubmitted_to_report = 0; + + 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); + let contains = pruned_log.contains(&tx_hash); + + // need to count all transactions, not just filtered, here + resubmitted_to_report += 1; + + if !contains { + log::trace!( + target: LOG_TARGET, + "[{:?}]: Resubmitting from retracted block {:?}", + tx_hash, + hash, + ); + } + !contains + }), + ); + + self.metrics.report(|metrics| { + metrics.block_transactions_resubmitted.inc_by(resubmitted_to_report) + }); + } + + 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 extra_pool = pool.clone(); + // After #5200 lands, this arguably might be moved to the + // handler of "all blocks notification". + self.ready_poll + .lock() + .trigger(hash_and_number.number, move || Box::new(extra_pool.validated_pool().ready())); + + if next_action.revalidate { + let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); + self.revalidation_queue.revalidate_later(hash_and_number.hash, hashes).await; + + self.revalidation_strategy.lock().clear(); + } + } +} + +#[async_trait] +impl MaintainedTransactionPool for BasicPool +where + Block: BlockT, + PoolApi: 'static + graph::ChainApi, +{ + async fn maintain(&self, event: ChainEvent) { + let prev_finalized_block = self.enactment_state.lock().recent_finalized_block(); + let compute_tree_route = |from, to| -> Result, String> { + match self.api.tree_route(from, to) { + Ok(tree_route) => Ok(tree_route), + Err(e) => + return Err(format!( + "Error occurred while computing tree_route from {from:?} to {to:?}: {e}" + )), + } + }; + let block_id_to_number = + |hash| self.api.block_id_to_number(&BlockId::Hash(hash)).map_err(|e| format!("{}", e)); + + let result = + self.enactment_state + .lock() + .update(&event, &compute_tree_route, &block_id_to_number); + + match result { + Err(msg) => { + log::trace!(target: LOG_TARGET, "{msg}"); + self.enactment_state.lock().force_update(&event); + }, + Ok(EnactmentAction::Skip) => return, + Ok(EnactmentAction::HandleFinalization) => {}, + Ok(EnactmentAction::HandleEnactment(tree_route)) => { + self.handle_enactment(tree_route).await; + }, + }; + + if let ChainEvent::Finalized { hash, tree_route } = event { + log::trace!( + target: LOG_TARGET, + "on-finalized enacted: {tree_route:?}, previously finalized: \ + {prev_finalized_block:?}", + ); + + for hash in tree_route.iter().chain(std::iter::once(&hash)) { + if let Err(e) = self.pool.validated_pool().on_block_finalized(*hash).await { + log::warn!( + target: LOG_TARGET, + "Error occurred while attempting to notify watchers about finalization {}: {}", + hash, e + ) + } + } + } + } +} diff --git a/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs b/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs new file mode 100644 index 000000000000..e373c0278d80 --- /dev/null +++ b/substrate/client/transaction-pool/src/transaction_pool_wrapper.rs @@ -0,0 +1,186 @@ +// 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 . + +//! Transaction pool wrapper. Provides a type for wrapping object providing actual implementation of +//! transaction pool. + +use crate::{ + builder::FullClientTransactionPool, + graph::{base_pool::Transaction, ExtrinsicFor, ExtrinsicHash}, + ChainApi, FullChainApi, ReadyIteratorFor, +}; +use async_trait::async_trait; +use sc_transaction_pool_api::{ + ChainEvent, ImportNotificationStream, LocalTransactionFor, LocalTransactionPool, + MaintainedTransactionPool, PoolStatus, ReadyTransactions, TransactionFor, TransactionPool, + TransactionSource, TransactionStatusStreamFor, TxHash, +}; +use sp_runtime::traits::Block as BlockT; +use std::{collections::HashMap, pin::Pin, sync::Arc}; + +/// The wrapper for actual object providing implementation of TransactionPool. +/// +/// This wraps actual implementation of the TransactionPool, e.g. fork-aware or single-state. +pub struct TransactionPoolWrapper( + pub Box>, +) +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue; + +#[async_trait] +impl TransactionPool for TransactionPoolWrapper +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + type Block = Block; + type Hash = ExtrinsicHash>; + type InPoolTransaction = Transaction< + ExtrinsicHash>, + ExtrinsicFor>, + >; + type Error = as ChainApi>::Error; + + async fn submit_at( + &self, + at: ::Hash, + source: TransactionSource, + xts: Vec>, + ) -> Result, Self::Error>>, Self::Error> { + self.0.submit_at(at, source, xts).await + } + + async fn submit_one( + &self, + at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> Result, Self::Error> { + self.0.submit_one(at, source, xt).await + } + + async fn submit_and_watch( + &self, + at: ::Hash, + source: TransactionSource, + xt: TransactionFor, + ) -> Result>>, Self::Error> { + self.0.submit_and_watch(at, source, xt).await + } + + async fn ready_at( + &self, + at: ::Hash, + ) -> ReadyIteratorFor> { + self.0.ready_at(at).await + } + + fn ready(&self) -> Box> + Send> { + self.0.ready() + } + + fn remove_invalid(&self, hashes: &[TxHash]) -> Vec> { + self.0.remove_invalid(hashes) + } + + fn futures(&self) -> Vec { + self.0.futures() + } + + fn status(&self) -> PoolStatus { + self.0.status() + } + + fn import_notification_stream(&self) -> ImportNotificationStream> { + self.0.import_notification_stream() + } + + fn on_broadcasted(&self, propagations: HashMap, Vec>) { + self.0.on_broadcasted(propagations) + } + + fn hash_of(&self, xt: &TransactionFor) -> TxHash { + self.0.hash_of(xt) + } + + fn ready_transaction(&self, hash: &TxHash) -> Option> { + self.0.ready_transaction(hash) + } + + async fn ready_at_with_timeout( + &self, + at: ::Hash, + timeout: std::time::Duration, + ) -> ReadyIteratorFor> { + self.0.ready_at_with_timeout(at, timeout).await + } +} + +#[async_trait] +impl MaintainedTransactionPool for TransactionPoolWrapper +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + async fn maintain(&self, event: ChainEvent) { + self.0.maintain(event).await; + } +} + +impl LocalTransactionPool for TransactionPoolWrapper +where + Block: BlockT, + Client: sp_api::ProvideRuntimeApi + + sc_client_api::BlockBackend + + sc_client_api::blockchain::HeaderBackend + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata + + 'static, + Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, +{ + type Block = Block; + type Hash = ExtrinsicHash>; + type Error = as ChainApi>::Error; + + fn submit_local( + &self, + at: ::Hash, + xt: LocalTransactionFor, + ) -> Result { + self.0.submit_local(at, xt) + } +} diff --git a/substrate/client/transaction-pool/tests/fatp.rs b/substrate/client/transaction-pool/tests/fatp.rs new file mode 100644 index 000000000000..9f343a9bd029 --- /dev/null +++ b/substrate/client/transaction-pool/tests/fatp.rs @@ -0,0 +1,2617 @@ +// 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 for fork-aware transaction pool. + +use fatp_common::{ + finalized_block_event, invalid_hash, new_best_block_event, pool, pool_with_api, + test_chain_with_forks, LOG_TARGET, SOURCE, +}; +use futures::{executor::block_on, task::Poll, FutureExt, StreamExt}; +use sc_transaction_pool::ChainApi; +use sc_transaction_pool_api::{ + error::{Error as TxPoolError, IntoPoolError}, + ChainEvent, MaintainedTransactionPool, TransactionPool, TransactionStatus, +}; +use sp_runtime::transaction_validity::InvalidTransaction; +use std::{sync::Arc, time::Duration}; +use substrate_test_runtime_client::AccountKeyring::*; +use substrate_test_runtime_transaction_pool::uxt; + +pub mod fatp_common; + +// Some ideas for tests: +// - view.ready iterator +// - stale transaction submission when there is single view only (expect error) +// - stale transaction submission when there are more views (expect ok if tx is ok for at least one +// view) +// - view count (e.g. same new block notified twice) +// - invalid with many views (different cases) +// +// review (from old pool) and maybe re-use: +// fn import_notification_to_pool_maintain_works() +// fn prune_tags_should_work() +// fn should_ban_invalid_transactions() +// fn should_correctly_prune_transactions_providing_more_than_one_tag() + +#[test] +fn fatp_no_view_future_and_ready_submit_one_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(header.hash(), SOURCE, xt0.clone()), + pool.submit_one(header.hash(), SOURCE, xt1.clone()), + ]; + + let results = block_on(futures::future::join_all(submissions)); + + assert!(results.iter().all(|r| { r.is_ok() })); +} + +#[test] +fn fatp_no_view_future_and_ready_submit_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + + let xts0 = (200..205).map(|i| uxt(Alice, i)).collect::>(); + let xts1 = (205..210).map(|i| uxt(Alice, i)).collect::>(); + let xts2 = (215..220).map(|i| uxt(Alice, i)).collect::>(); + + let submissions = vec![ + pool.submit_at(header.hash(), SOURCE, xts0.clone()), + pool.submit_at(header.hash(), SOURCE, xts1.clone()), + pool.submit_at(header.hash(), SOURCE, xts2.clone()), + ]; + + let results = block_on(futures::future::join_all(submissions)); + + assert!(results.into_iter().flat_map(|x| x.unwrap()).all(|r| { r.is_ok() })); +} + +#[test] +fn fatp_no_view_submit_already_imported_reports_error() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + + let xts0 = (215..220).map(|i| uxt(Alice, i)).collect::>(); + let xts1 = xts0.clone(); + + let submission_ok = pool.submit_at(header.hash(), SOURCE, xts0.clone()); + let results = block_on(submission_ok); + assert!(results.unwrap().into_iter().all(|r| r.is_ok())); + + let submission_failing = pool.submit_at(header.hash(), SOURCE, xts1.clone()); + let results = block_on(submission_failing); + + assert!(results + .unwrap() + .into_iter() + .all(|r| { matches!(r.unwrap_err().0, TxPoolError::AlreadyImported(_)) })); +} + +#[test] +fn fatp_one_view_future_and_ready_submit_one_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + // let header01b = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(header.hash(), SOURCE, xt0.clone()), + pool.submit_one(header.hash(), SOURCE, xt1.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + assert_pool_status!(header.hash(), &pool, 1, 1); +} + +#[test] +fn fatp_one_view_future_and_ready_submit_many_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + // let header01b = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header.hash()); + block_on(pool.maintain(event)); + + let xts0 = (200..205).map(|i| uxt(Alice, i)).collect::>(); + let xts1 = (205..210).map(|i| uxt(Alice, i)).collect::>(); + let xts2 = (215..220).map(|i| uxt(Alice, i)).collect::>(); + + let submissions = vec![ + pool.submit_at(header.hash(), SOURCE, xts0.clone()), + pool.submit_at(header.hash(), SOURCE, xts1.clone()), + pool.submit_at(header.hash(), SOURCE, xts2.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + assert_pool_status!(header.hash(), &pool, 10, 5); +} + +#[test] +fn fatp_one_view_stale_submit_one_fails() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 100); + let submissions = vec![pool.submit_one(invalid_hash(), SOURCE, xt0.clone())]; + let results = block_on(futures::future::join_all(submissions)); + + //xt0 should be stale + assert!(matches!( + &results[0].as_ref().unwrap_err().0, + TxPoolError::InvalidTransaction(InvalidTransaction::Stale,) + )); + + assert_pool_status!(header.hash(), &pool, 0, 0); +} + +#[test] +fn fatp_one_view_stale_submit_many_fails() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header.hash()); + block_on(pool.maintain(event)); + + let xts0 = (100..105).map(|i| uxt(Alice, i)).collect::>(); + let xts1 = (105..110).map(|i| uxt(Alice, i)).collect::>(); + let xts2 = (195..201).map(|i| uxt(Alice, i)).collect::>(); + + let submissions = vec![ + pool.submit_at(header.hash(), SOURCE, xts0.clone()), + pool.submit_at(header.hash(), SOURCE, xts1.clone()), + pool.submit_at(header.hash(), SOURCE, xts2.clone()), + ]; + + let results = block_on(futures::future::join_all(submissions)); + + //xts2 contains one ready transaction (nonce:200) + let mut results = results.into_iter().flat_map(|x| x.unwrap()).collect::>(); + log::debug!("{:#?}", results); + assert!(results.pop().unwrap().is_ok()); + assert!(results.into_iter().all(|r| { + matches!( + &r.as_ref().unwrap_err().0, + TxPoolError::InvalidTransaction(InvalidTransaction::Stale,) + ) + })); + + assert_pool_status!(header.hash(), &pool, 1, 0); +} + +#[test] +fn fatp_one_view_future_turns_to_ready_works() { + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + let at = header.hash(); + let event = new_best_block_event(&pool, None, at); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 201); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + assert!(pool.ready().count() == 0); + assert_pool_status!(at, &pool, 0, 1); + + let xt1 = uxt(Alice, 200); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let ready: Vec<_> = pool.ready().map(|v| (*v.data).clone()).collect(); + assert_eq!(ready, vec![xt1, xt0]); + assert_pool_status!(at, &pool, 2, 0); +} + +#[test] +fn fatp_one_view_ready_gets_pruned() { + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + let block1 = header.hash(); + let event = new_best_block_event(&pool, None, block1); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let pending: Vec<_> = pool.ready().map(|v| (*v.data).clone()).collect(); + assert_eq!(pending, vec![xt0.clone()]); + assert_eq!(pool.status_all()[&block1].ready, 1); + + let header = api.push_block(2, vec![xt0], true); + let block2 = header.hash(); + let event = new_best_block_event(&pool, Some(block1), block2); + block_on(pool.maintain(event)); + assert_pool_status!(block2, &pool, 0, 0); + assert!(pool.ready().count() == 0); +} + +#[test] +fn fatp_one_view_ready_turns_to_stale_works() { + let (pool, api, _) = pool(); + + let header = api.push_block(1, vec![], true); + let block1 = header.hash(); + let event = new_best_block_event(&pool, None, block1); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let pending: Vec<_> = pool.ready().map(|v| (*v.data).clone()).collect(); + assert_eq!(pending, vec![xt0.clone()]); + assert_eq!(pool.status_all()[&block1].ready, 1); + + let header = api.push_block(2, vec![], true); + let block2 = header.hash(); + //tricky: typically the block2 shall contain conflicting transaction for Alice. In this test we + //want to check revalidation, so we manually adjust nonce. + api.set_nonce(block2, Alice.into(), 201); + let event = new_best_block_event(&pool, Some(block1), block2); + //note: blocking revalidation (w/o background worker) which is used in this test will detect + // xt0 is stale + block_on(pool.maintain(event)); + //todo: should it work at all? (it requires better revalidation: mempool keeping validated txs) + // assert_pool_status!(block2, &pool, 0, 0); + // assert!(pool.ready(block2).unwrap().count() == 0); +} + +#[test] +fn fatp_two_views_future_and_ready_submit_one() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let genesis = api.genesis_hash(); + let header01a = api.push_block(1, vec![], true); + let header01b = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01a.hash()); + block_on(pool.maintain(event)); + + let event = new_best_block_event(&pool, None, header01b.hash()); + block_on(pool.maintain(event)); + + api.set_nonce(header01b.hash(), Alice.into(), 202); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(genesis, SOURCE, xt0.clone()), + pool.submit_one(genesis, SOURCE, xt1.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + assert_pool_status!(header01a.hash(), &pool, 1, 1); + assert_pool_status!(header01b.hash(), &pool, 1, 0); +} + +#[test] +fn fatp_two_views_future_and_ready_submit_many() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header01a = api.push_block(1, vec![], true); + let header01b = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01a.hash()); + block_on(pool.maintain(event)); + + let event = new_best_block_event(&pool, None, header01b.hash()); + block_on(pool.maintain(event)); + + api.set_nonce(header01b.hash(), Alice.into(), 215); + + let xts0 = (200..205).map(|i| uxt(Alice, i)).collect::>(); + let xts1 = (205..210).map(|i| uxt(Alice, i)).collect::>(); + let xts2 = (215..220).map(|i| uxt(Alice, i)).collect::>(); + + let submissions = vec![ + pool.submit_at(invalid_hash(), SOURCE, xts0.clone()), + pool.submit_at(invalid_hash(), SOURCE, xts1.clone()), + pool.submit_at(invalid_hash(), SOURCE, xts2.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + log::debug!(target:LOG_TARGET, "stats: {:#?}", pool.status_all()); + + assert_pool_status!(header01a.hash(), &pool, 10, 5); + assert_pool_status!(header01b.hash(), &pool, 5, 0); +} + +#[test] +fn fatp_two_views_submit_many_variations() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 206); + let xt1 = uxt(Alice, 206); + + let result = block_on(pool.submit_one(invalid_hash(), SOURCE, xt1.clone())); + assert!(result.is_ok()); + + let header01a = api.push_block(1, vec![xt0.clone()], true); + let header01b = api.push_block(1, vec![xt0.clone()], true); + + api.set_nonce(header01a.hash(), Alice.into(), 201); + api.set_nonce(header01b.hash(), Alice.into(), 202); + + let event = new_best_block_event(&pool, None, header01a.hash()); + block_on(pool.maintain(event)); + + let event = new_best_block_event(&pool, None, header01b.hash()); + block_on(pool.maintain(event)); + + let mut xts = (199..204).map(|i| uxt(Alice, i)).collect::>(); + xts.push(xt0); + xts.push(xt1); + + let results = block_on(pool.submit_at(invalid_hash(), SOURCE, xts.clone())).unwrap(); + + log::debug!(target:LOG_TARGET, "res: {:#?}", results); + log::debug!(target:LOG_TARGET, "stats: {:#?}", pool.status_all()); + + (0..2).for_each(|i| { + assert!(matches!( + results[i].as_ref().unwrap_err().0, + TxPoolError::InvalidTransaction(InvalidTransaction::Stale,) + )); + }); + //note: tx at 2 is valid at header01a and invalid at header01b + (2..5).for_each(|i| { + assert_eq!(*results[i].as_ref().unwrap(), api.hash_and_length(&xts[i]).0); + }); + //xt0 at index 5 (transaction from the imported block, gets banned when pruned) + assert!(matches!(results[5].as_ref().unwrap_err().0, TxPoolError::TemporarilyBanned)); + //xt1 at index 6 + assert!(matches!(results[6].as_ref().unwrap_err().0, TxPoolError::AlreadyImported(_))); +} + +#[test] +fn fatp_linear_progress() { + sp_tracing::try_init_simple(); + + let (api, forks) = test_chain_with_forks::chain(None); + let (pool, _) = pool_with_api(api.clone()); + + let f11 = forks[1][1].hash(); + let f13 = forks[1][3].hash(); + + let event = new_best_block_event(&pool, None, f11); + block_on(pool.maintain(event)); + + let xt0 = uxt(Bob, 203); + let submissions = vec![pool.submit_one(invalid_hash(), SOURCE, xt0.clone())]; + + block_on(futures::future::join_all(submissions)); + + let event = new_best_block_event(&pool, Some(f11), f13); + log::debug!(target:LOG_TARGET, "event: {:#?}", event); + block_on(pool.maintain(event)); + + //note: we only keep tip of the fork + assert_eq!(pool.active_views_count(), 1); + assert_pool_status!(f13, &pool, 1, 0); +} + +#[test] +fn fatp_linear_old_ready_becoming_stale() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + // Our initial transactions + let xts = vec![uxt(Alice, 300), uxt(Alice, 301), uxt(Alice, 302)]; + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + xts.into_iter().for_each(|xt| { + block_on(pool.submit_one(invalid_hash(), SOURCE, xt)).unwrap(); + }); + assert_eq!(pool.status_all()[&header01.hash()].ready, 0); + assert_eq!(pool.status_all()[&header01.hash()].future, 3); + + // Import enough blocks to make our transactions stale (longevity is 64) + let mut prev_header = header01; + for n in 2..66 { + let header = api.push_block(n, vec![], true); + let event = new_best_block_event(&pool, Some(prev_header.hash()), header.hash()); + block_on(pool.maintain(event)); + + if n == 65 { + assert_eq!(pool.status_all()[&header.hash()].ready, 0); + assert_eq!(pool.status_all()[&header.hash()].future, 0); + } else { + assert_eq!(pool.status_all()[&header.hash()].ready, 0); + assert_eq!(pool.status_all()[&header.hash()].future, 3); + } + prev_header = header; + } +} + +#[test] +fn fatp_fork_reorg() { + sp_tracing::try_init_simple(); + + let (api, forks) = test_chain_with_forks::chain(None); + let (pool, _) = pool_with_api(api.clone()); + + let f03 = forks[0][3].hash(); + let f13 = forks[1][3].hash(); + + let event = new_best_block_event(&pool, None, f03); + block_on(pool.maintain(event)); + + let xt0 = uxt(Bob, 203); + let xt1 = uxt(Bob, 204); + let xt2 = uxt(Alice, 203); + let submissions = vec![ + pool.submit_one(invalid_hash(), SOURCE, xt0.clone()), + pool.submit_one(invalid_hash(), SOURCE, xt1.clone()), + pool.submit_one(invalid_hash(), SOURCE, xt2.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + let event = new_best_block_event(&pool, Some(f03), f13); + log::debug!(target:LOG_TARGET, "event: {:#?}", event); + block_on(pool.maintain(event)); + + assert_pool_status!(f03, &pool, 1, 2); + assert_pool_status!(f13, &pool, 6, 0); + + //check if ready for block[1][3] contains resubmitted transactions + let mut expected = forks[0] + .iter() + .take(4) + .flat_map(|h| block_on(api.block_body(h.hash())).unwrap().unwrap()) + .collect::>(); + expected.extend_from_slice(&[xt0, xt1, xt2]); + + let ready_f13 = pool.ready().collect::>(); + expected.iter().for_each(|e| { + assert!(ready_f13.iter().any(|v| *v.data == *e)); + }); + assert_eq!(expected.len(), ready_f13.len()); +} + +#[test] +fn fatp_fork_do_resubmit_same_tx() { + let xt = uxt(Alice, 200); + + let (pool, api, _) = pool(); + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + + block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone())).unwrap(); + assert_eq!(pool.status_all()[&header01.hash()].ready, 1); + + let header02a = api.push_block(1, vec![xt.clone()], true); + let header02b = api.push_block(1, vec![xt], true); + + let event = new_best_block_event(&pool, Some(header02a.hash()), header02b.hash()); + api.set_nonce(header02a.hash(), Alice.into(), 201); + block_on(pool.maintain(event)); + assert_eq!(pool.status_all()[&header02b.hash()].ready, 0); + + let event = new_best_block_event(&pool, Some(api.genesis_hash()), header02b.hash()); + api.set_nonce(header02b.hash(), Alice.into(), 201); + block_on(pool.maintain(event)); + + assert_eq!(pool.status_all()[&header02b.hash()].ready, 0); +} + +#[test] +fn fatp_fork_stale_rejected() { + sp_tracing::try_init_simple(); + + // note: there are no xts in blocks on fork 0! + let (api, forks) = test_chain_with_forks::chain(Some(&|f, b| match (f, b) { + (0, _) => false, + _ => true, + })); + let (pool, _) = pool_with_api(api.clone()); + + let f03 = forks[0][3].hash(); + let f13 = forks[1][3].hash(); + + // n:201 n:202 n:203 <-- alice nonce + // F01 - F02 - F03 <-- xt2 is stale + // / + // F00 + // \ + // F11[t0] - F12[t1] - F13[t2] + // n:201 n:202 n:203 <-- bob nonce + // + // t0 = uxt(Bob,200) + // t1 = uxt(Bob,201) + // t2 = uxt(Bob,201) + // xt0 = uxt(Bob, 203) + // xt1 = uxt(Bob, 204) + // xt2 = uxt(Alice, 201); + + let event = new_best_block_event(&pool, None, f03); + block_on(pool.maintain(event)); + + let xt0 = uxt(Bob, 203); + let xt1 = uxt(Bob, 204); + let xt2 = uxt(Alice, 201); + let submissions = vec![ + pool.submit_one(invalid_hash(), SOURCE, xt0.clone()), + pool.submit_one(invalid_hash(), SOURCE, xt1.clone()), + pool.submit_one(invalid_hash(), SOURCE, xt2.clone()), + ]; + let submission_results = block_on(futures::future::join_all(submissions)); + let futures_f03 = pool.futures(); + + //xt2 should be stale + assert!(matches!( + &submission_results[2].as_ref().unwrap_err().0, + TxPoolError::InvalidTransaction(InvalidTransaction::Stale,) + )); + + let event = new_best_block_event(&pool, Some(f03), f13); + log::debug!(target:LOG_TARGET, "event: {:#?}", event); + block_on(pool.maintain(event)); + + assert_pool_status!(f03, &pool, 0, 2); + + //xt2 was removed from the pool, it is not becoming future: + //note: theoretically we could keep xt2 in the pool, even if it was reported as stale. But it + //seems to be an unnecessary complication. + assert_pool_status!(f13, &pool, 2, 0); + + let futures_f13 = pool.futures(); + let ready_f13 = pool.ready().collect::>(); + assert!(futures_f13.iter().next().is_none()); + assert!(futures_f03.iter().any(|v| *v.data == xt0)); + assert!(futures_f03.iter().any(|v| *v.data == xt1)); + assert!(ready_f13.iter().any(|v| *v.data == xt0)); + assert!(ready_f13.iter().any(|v| *v.data == xt1)); +} + +#[test] +fn fatp_fork_no_xts_ready_switch_to_future() { + //this scenario w/o xts is not likely to happen, but similar thing (xt changing from ready to + //future) could occur e.g. when runtime was updated on fork1. + sp_tracing::try_init_simple(); + + // note: there are no xts in blocks! + let (api, forks) = test_chain_with_forks::chain(Some(&|_, _| false)); + let (pool, _) = pool_with_api(api.clone()); + + let f03 = forks[0][3].hash(); + let f12 = forks[1][2].hash(); + + let event = new_best_block_event(&pool, None, f03); + block_on(pool.maintain(event)); + + // xt0 is ready on f03, but future on f12, f13 + let xt0 = uxt(Alice, 203); + let submissions = vec![pool.submit_one(invalid_hash(), SOURCE, xt0.clone())]; + block_on(futures::future::join_all(submissions)); + + let event = new_best_block_event(&pool, Some(f03), f12); + block_on(pool.maintain(event)); + + assert_pool_status!(f03, &pool, 1, 0); + // f12 was not updated - xt0 is still ready there + // (todo: can we do better? shall we revalidate all future xts?) + assert_pool_status!(f12, &pool, 1, 0); + + //xt0 becomes future, and this may only happen after view revalidation (which happens on + //finalization). So trigger it. + let event = finalized_block_event(&pool, api.genesis_hash(), f12); + block_on(pool.maintain(event)); + + // f03 still dangling + assert_eq!(pool.active_views_count(), 2); + + // wait 10 blocks for revalidation and 1 extra for applying revalidation results + let mut prev_header = forks[1][2].clone(); + log::debug!("====> {:?}", prev_header); + for _ in 3..=12 { + let header = api.push_block_with_parent(prev_header.hash(), vec![], true); + let event = finalized_block_event(&pool, prev_header.hash(), header.hash()); + block_on(pool.maintain(event)); + prev_header = header; + } + + assert_pool_status!(prev_header.hash(), &pool, 0, 1); +} + +#[test] +fn fatp_ready_at_does_not_trigger() { + sp_tracing::try_init_simple(); + + let (api, forks) = test_chain_with_forks::chain(None); + let (pool, _) = pool_with_api(api.clone()); + + let f03 = forks[0][3].hash(); + let f13 = forks[1][3].hash(); + + assert!(pool.ready_at(f03).now_or_never().is_none()); + assert!(pool.ready_at(f13).now_or_never().is_none()); +} + +#[test] +fn fatp_ready_at_does_not_trigger_after_submit() { + sp_tracing::try_init_simple(); + + let (api, forks) = test_chain_with_forks::chain(None); + let (pool, _) = pool_with_api(api.clone()); + + let xt0 = uxt(Alice, 200); + let _ = block_on(pool.submit_one(invalid_hash(), SOURCE, xt0)); + + let f03 = forks[0][3].hash(); + let f13 = forks[1][3].hash(); + + assert!(pool.ready_at(f03).now_or_never().is_none()); + assert!(pool.ready_at(f13).now_or_never().is_none()); +} + +#[test] +fn fatp_ready_at_triggered_by_maintain() { + //this scenario w/o xts is not likely to happen, but similar thing (xt changing from ready to + //future) could occur e.g. when runtime was updated on fork1. + sp_tracing::try_init_simple(); + let (api, forks) = test_chain_with_forks::chain(Some(&|_, _| false)); + let (pool, _) = pool_with_api(api.clone()); + + let f03 = forks[0][3].hash(); + let f13 = forks[1][3].hash(); + + assert!(pool.ready_at(f03).now_or_never().is_none()); + + let event = new_best_block_event(&pool, None, f03); + block_on(pool.maintain(event)); + + assert!(pool.ready_at(f03).now_or_never().is_some()); + + let xt0 = uxt(Alice, 203); + let submissions = vec![pool.submit_one(invalid_hash(), SOURCE, xt0.clone())]; + block_on(futures::future::join_all(submissions)); + + let event = new_best_block_event(&pool, Some(f03), f13); + log::debug!(target:LOG_TARGET, "event: {:#?}", event); + assert!(pool.ready_at(f13).now_or_never().is_none()); + block_on(pool.maintain(event)); + assert!(pool.ready_at(f03).now_or_never().is_some()); + assert!(pool.ready_at(f13).now_or_never().is_some()); +} + +#[test] +fn fatp_ready_at_triggered_by_maintain2() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header01 = api.push_block(1, vec![], true); + + let xt0 = uxt(Alice, 200); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + // let (pool, api, _guard) = maintained_pool(); + // let header = api.push_block(1, vec![], true); + // + // let xt1 = uxt(Alice, 209); + // + // block_on(pool.submit_one(api.expect_hash_from_number(1), SOURCE, xt1.clone())) + // .expect("1. Imported"); + + let noop_waker = futures::task::noop_waker(); + let mut context = futures::task::Context::from_waker(&noop_waker); + + let mut ready_set_future = pool.ready_at(header01.hash()); + if ready_set_future.poll_unpin(&mut context).is_ready() { + panic!("Ready set should not be ready before block update!"); + } + + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + // block_on(pool.maintain(block_event(header))); + + match ready_set_future.poll_unpin(&mut context) { + Poll::Pending => { + panic!("Ready set should become ready after block update!"); + }, + Poll::Ready(iterator) => { + let data = iterator.collect::>(); + assert_eq!(data.len(), 1); + }, + } +} + +#[test] +fn fatp_linear_progress_finalization() { + sp_tracing::try_init_simple(); + + let (api, forks) = test_chain_with_forks::chain(None); + let (pool, _) = pool_with_api(api.clone()); + + let f00 = forks[0][0].hash(); + let f12 = forks[1][2].hash(); + let f14 = forks[1][4].hash(); + + let event = new_best_block_event(&pool, None, f00); + block_on(pool.maintain(event)); + + let xt0 = uxt(Bob, 204); + let submissions = vec![pool.submit_one(invalid_hash(), SOURCE, xt0.clone())]; + block_on(futures::future::join_all(submissions)); + + let event = new_best_block_event(&pool, Some(f00), f12); + block_on(pool.maintain(event)); + assert_pool_status!(f12, &pool, 0, 1); + assert_eq!(pool.active_views_count(), 1); + + log::debug!(target:LOG_TARGET, "stats: {:#?}", pool.status_all()); + + let event = ChainEvent::Finalized { hash: f14, tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + + log::debug!(target:LOG_TARGET, "stats: {:#?}", pool.status_all()); + + assert_eq!(pool.active_views_count(), 1); + assert_pool_status!(f14, &pool, 1, 0); +} + +#[test] +fn fatp_fork_finalization_removes_stale_views() { + sp_tracing::try_init_simple(); + + let (api, forks) = test_chain_with_forks::chain(None); + let (pool, _) = pool_with_api(api.clone()); + + let f00 = forks[0][0].hash(); + let f12 = forks[1][2].hash(); + let f14 = forks[1][4].hash(); + let f02 = forks[0][2].hash(); + let f03 = forks[0][3].hash(); + let f04 = forks[0][4].hash(); + + let xt0 = uxt(Bob, 203); + let submissions = vec![pool.submit_one(invalid_hash(), SOURCE, xt0.clone())]; + block_on(futures::future::join_all(submissions)); + + let event = new_best_block_event(&pool, Some(f00), f12); + block_on(pool.maintain(event)); + let event = new_best_block_event(&pool, Some(f00), f14); + block_on(pool.maintain(event)); + let event = new_best_block_event(&pool, Some(f00), f02); + block_on(pool.maintain(event)); + + //only views at the tips of the forks are kept + assert_eq!(pool.active_views_count(), 2); + + log::debug!(target:LOG_TARGET, "stats: {:#?}", pool.status_all()); + + let event = ChainEvent::Finalized { hash: f03, tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + log::debug!(target:LOG_TARGET, "stats: {:#?}", pool.status_all()); + // note: currently the pruning views only cleans views with block number less than finalized + // block. views with higher number on other forks are not cleaned (will be done in next round). + assert_eq!(pool.active_views_count(), 2); + + let event = ChainEvent::Finalized { hash: f04, tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + assert_eq!(pool.active_views_count(), 1); +} + +#[test] +fn fatp_watcher_invalid_fails_on_submission() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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, 150); + api.add_invalid(&xt0); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())); + let xt0_watcher = xt0_watcher.map(|_| ()); + + assert_pool_status!(header01.hash(), &pool, 0, 0); + assert!(matches!( + xt0_watcher.unwrap_err().into_pool_error(), + Ok(TxPoolError::InvalidTransaction(InvalidTransaction::Stale)) + )); +} + +#[test] +fn fatp_watcher_invalid_single_revalidation() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, Some(api.genesis_hash()), header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + api.add_invalid(&xt0); + + let header02 = api.push_block_with_parent(header01.hash(), vec![], true); + let event = finalized_block_event(&pool, header01.hash(), header02.hash()); + block_on(pool.maintain(event)); + + // wait 10 blocks for revalidation + let mut prev_header = header02; + for n in 3..=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 xt0_events = futures::executor::block_on_stream(xt0_watcher).collect::>(); + log::debug!("xt0_events: {:#?}", xt0_events); + assert_eq!(xt0_events, vec![TransactionStatus::Ready, TransactionStatus::Invalid]); +} + +#[test] +fn fatp_watcher_invalid_single_revalidation2() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 200); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + assert_eq!(pool.mempool_len(), (0, 1)); + api.add_invalid(&xt0); + + 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_events = futures::executor::block_on_stream(xt0_watcher).collect::>(); + log::debug!("xt0_events: {:#?}", xt0_events); + assert_eq!(xt0_events, vec![TransactionStatus::Invalid]); + assert_eq!(pool.mempool_len(), (0, 0)); +} + +#[test] +fn fatp_watcher_invalid_single_revalidation3() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 150); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + assert_eq!(pool.mempool_len(), (0, 1)); + + let header01 = api.push_block(1, vec![], true); + let event = finalized_block_event(&pool, api.genesis_hash(), header01.hash()); + block_on(pool.maintain(event)); + + // wait 10 blocks for revalidation + let mut prev_header = header01; + for n in 2..=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 xt0_events = futures::executor::block_on_stream(xt0_watcher).collect::>(); + log::debug!("xt0_events: {:#?}", xt0_events); + assert_eq!(xt0_events, vec![TransactionStatus::Invalid]); + assert_eq!(pool.mempool_len(), (0, 0)); +} + +#[test] +fn fatp_watcher_future() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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, 202); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 0, 1); + + let header02 = api.push_block(2, vec![], true); + let event = ChainEvent::Finalized { + hash: header02.hash(), + tree_route: Arc::from(vec![header01.hash()]), + }; + block_on(pool.maintain(event)); + + assert_pool_status!(header02.hash(), &pool, 0, 1); + + let xt0_events = block_on(xt0_watcher.take(1).collect::>()); + assert_eq!(xt0_events, vec![TransactionStatus::Future]); +} + +#[test] +fn fatp_watcher_ready() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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 xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 1, 0); + + let header02 = api.push_block(2, vec![], true); + let event = ChainEvent::Finalized { + hash: header02.hash(), + tree_route: Arc::from(vec![header01.hash()]), + }; + block_on(pool.maintain(event)); + + assert_pool_status!(header02.hash(), &pool, 1, 0); + + let xt0_events = block_on(xt0_watcher.take(1).collect::>()); + assert_eq!(xt0_events, vec![TransactionStatus::Ready]); +} + +#[test] +fn fatp_watcher_finalized() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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 xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 1, 0); + + let header02 = api.push_block(2, vec![xt0], true); + let event = ChainEvent::Finalized { + hash: header02.hash(), + tree_route: Arc::from(vec![header01.hash()]), + }; + block_on(pool.maintain(event)); + + assert_pool_status!(header02.hash(), &pool, 0, 0); + + let xt0_events = block_on(xt0_watcher.collect::>()); + assert_eq!( + xt0_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_in_block() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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 xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 1, 0); + + let header02 = api.push_block(2, vec![xt0], true); + + let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); + block_on(pool.maintain(event)); + let xt0_events = block_on(xt0_watcher.take(2).collect::>()); + assert_eq!( + xt0_events, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header02.hash(), 0)),] + ); +} + +#[test] +fn fatp_watcher_future_and_finalized() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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, 202); + + let submissions = vec![ + pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone()), + pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone()), + ]; + + let mut submissions = block_on(futures::future::join_all(submissions)); + let xt1_watcher = submissions.remove(1).unwrap(); + let xt0_watcher = submissions.remove(0).unwrap(); + + assert_pool_status!(header01.hash(), &pool, 1, 1); + + let header02 = api.push_block(2, vec![xt0], true); + let event = ChainEvent::Finalized { + hash: header02.hash(), + tree_route: Arc::from(vec![header01.hash()]), + }; + // let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); + block_on(pool.maintain(event)); + + assert_pool_status!(header02.hash(), &pool, 0, 1); + + let xt1_status = block_on(xt1_watcher.take(1).collect::>()); + assert_eq!(xt1_status, vec![TransactionStatus::Future]); + let xt0_status = block_on(xt0_watcher.collect::>()); + assert_eq!( + xt0_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_two_finalized_in_different_block() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Dave.into(), 200); + + 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, 201); + let xt2 = uxt(Bob, 200); + let xt3 = uxt(Dave, 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(); + + assert_pool_status!(header01.hash(), &pool, 3, 0); + + let header02 = api.push_block(2, vec![xt3.clone(), xt2.clone(), xt0.clone()], true); + api.set_nonce(header02.hash(), Alice.into(), 201); + //note: no maintain for block02 (!) + + let header03 = api.push_block(3, vec![xt1.clone()], true); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header03.hash()))); + + assert_pool_status!(header03.hash(), &pool, 0, 0); + + let xt1_status = futures::executor::block_on_stream(xt1_watcher).collect::>(); + + assert_eq!( + xt1_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 0)), + TransactionStatus::Finalized((header03.hash(), 0)) + ] + ); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + + log::debug!("xt0_status: {:#?}", xt0_status); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 2)), + TransactionStatus::Finalized((header02.hash(), 2)) + ] + ); + + let xt2_status = futures::executor::block_on_stream(xt2_watcher).collect::>(); + log::debug!("xt2_status: {:#?}", xt2_status); + + assert_eq!( + xt2_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 1)), + TransactionStatus::Finalized((header02.hash(), 1)) + ] + ); +} + +#[test] +fn fatp_no_view_pool_watcher_two_finalized_in_different_block() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Dave.into(), 200); + + let header01 = api.push_block(1, vec![], true); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Bob, 200); + let xt3 = uxt(Dave, 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 header02 = api.push_block(2, vec![xt3.clone(), xt2.clone(), xt0.clone()], true); + api.set_nonce(header02.hash(), Alice.into(), 201); + api.set_nonce(header02.hash(), Bob.into(), 201); + api.set_nonce(header02.hash(), Dave.into(), 201); + //note: no maintain for block02 (!) + + let header03 = api.push_block(3, vec![xt1.clone()], true); + api.set_nonce(header03.hash(), Alice.into(), 202); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header03.hash()))); + + assert_pool_status!(header03.hash(), &pool, 0, 0); + + let xt1_status = futures::executor::block_on_stream(xt1_watcher).collect::>(); + + log::debug!("xt1_status: {:#?}", xt1_status); + + assert_eq!( + xt1_status, + vec![ + TransactionStatus::InBlock((header03.hash(), 0)), + TransactionStatus::Finalized((header03.hash(), 0)) + ] + ); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + + log::debug!("xt0_status: {:#?}", xt0_status); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::InBlock((header02.hash(), 2)), + TransactionStatus::Finalized((header02.hash(), 2)) + ] + ); + + let xt2_status = futures::executor::block_on_stream(xt2_watcher).collect::>(); + log::debug!("xt2_status: {:#?}", xt2_status); + + assert_eq!( + xt2_status, + vec![ + TransactionStatus::InBlock((header02.hash(), 1)), + TransactionStatus::Finalized((header02.hash(), 1)) + ] + ); +} + +#[test] +fn fatp_watcher_in_block_across_many_blocks() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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, 201); + let xt2 = uxt(Alice, 202); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + assert_pool_status!(header01.hash(), &pool, 2, 0); + + let header02 = api.push_block(2, vec![], true); + let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); + block_on(pool.maintain(event)); + + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + //note 1: transaction is not submitted to views that are not at the tip of the fork + assert_eq!(pool.active_views_count(), 1); + assert_eq!(pool.inactive_views_count(), 1); + assert_pool_status!(header02.hash(), &pool, 3, 0); + + let header03 = api.push_block(3, vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(header02.hash()), header03.hash()); + block_on(pool.maintain(event)); + + assert_pool_status!(header03.hash(), &pool, 2, 0); + + 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, TransactionStatus::InBlock((header03.hash(), 0)),] + ); +} + +#[test] +fn fatp_watcher_in_block_across_many_blocks2() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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, 201); + let xt2 = uxt(Alice, 202); + + 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); + + let header02 = api.push_block(2, vec![], true); + let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); + block_on(pool.maintain(event)); + + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + //note 1: transaction is not submitted to views that are not at the tip of the fork + assert_eq!(pool.active_views_count(), 1); + assert_eq!(pool.inactive_views_count(), 1); + assert_pool_status!(header02.hash(), &pool, 3, 0); + + let header03 = api.push_block(3, vec![xt0.clone()], true); + let header04 = api.push_block(4, vec![xt1.clone()], true); + let event = new_best_block_event(&pool, Some(header02.hash()), header04.hash()); + block_on(pool.maintain(event)); + + assert_pool_status!(header04.hash(), &pool, 1, 0); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).take(2).collect::>(); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); + + log::debug!("xt0_status: {:#?}", xt0_status); + log::debug!("xt1_status: {:#?}", xt1_status); + assert_eq!( + xt0_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header03.hash(), 0)),] + ); + assert_eq!( + xt1_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header04.hash(), 0)),] + ); +} + +#[test] +fn fatp_watcher_dropping_listener_should_work() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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); + + // intentionally drop the listener - nothing should panic. + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + assert_pool_status!(header01.hash(), &pool, 1, 0); + + let header02 = api.push_block(2, vec![], true); + let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); + block_on(pool.maintain(event)); +} + +#[test] +fn fatp_watcher_fork_retract_and_finalize() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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 xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + assert_pool_status!(header01.hash(), &pool, 1, 0); + + let header02a = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(header01.hash()), header02a.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header02a.hash(), &pool, 0, 0); + + let header02b = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); + let event = ChainEvent::Finalized { + hash: header02b.hash(), + tree_route: Arc::from(vec![header01.hash()]), + }; + block_on(pool.maintain(event)); + assert_pool_status!(header02b.hash(), &pool, 0, 0); + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + + log::debug!("xt0_status: {:#?}", xt0_status); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02a.hash(), 0)), + TransactionStatus::InBlock((header02b.hash(), 0)), + TransactionStatus::Finalized((header02b.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_retract_all_forks() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + + let header02a = api.push_block_with_parent(genesis, vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(genesis), header02a.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header02a.hash(), &pool, 0, 0); + + let header02b = api.push_block_with_parent(genesis, vec![xt1.clone()], true); + let event = new_best_block_event(&pool, Some(header02a.hash()), header02b.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header02b.hash(), &pool, 1, 0); + + let header02c = api.push_block_with_parent(genesis, vec![], true); + let event = + ChainEvent::Finalized { hash: header02c.hash(), tree_route: Arc::from(vec![genesis]) }; + block_on(pool.maintain(event)); + assert_pool_status!(header02c.hash(), &pool, 2, 0); +} + +#[test] +fn fatp_watcher_finalizing_forks() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + api.set_nonce(api.genesis_hash(), Dave.into(), 200); + api.set_nonce(api.genesis_hash(), Eve.into(), 200); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + let xt2 = uxt(Charlie, 200); + let xt3 = uxt(Dave, 200); + let xt4 = uxt(Eve, 200); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let header01 = api.push_block(1, vec![xt0.clone()], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header01.hash()))); + + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let header02a = api.push_block_with_parent(header01.hash(), vec![xt1.clone()], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02a.hash()))); + + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + let header03a = api.push_block_with_parent(header02a.hash(), vec![xt2.clone()], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header02a.hash()), header03a.hash()))); + + let xt3_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + let header02b = api.push_block_with_parent(header01.hash(), vec![xt3.clone()], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02b.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header02b.hash()))); + + let xt4_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt4.clone())).unwrap(); + let header03b = api.push_block_with_parent(header02b.hash(), vec![xt4.clone()], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header02b.hash()), header03b.hash()))); + + let header04b = + api.push_block_with_parent(header03b.hash(), vec![xt1.clone(), xt2.clone()], true); + block_on(pool.maintain(new_best_block_event(&pool, Some(header03b.hash()), header04b.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, header02b.hash(), header04b.hash()))); + + //======================= + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).collect::>(); + let xt2_status = futures::executor::block_on_stream(xt2_watcher).collect::>(); + let xt3_status = futures::executor::block_on_stream(xt3_watcher).collect::>(); + let xt4_status = futures::executor::block_on_stream(xt4_watcher).collect::>(); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::InBlock((header01.hash(), 0)), + TransactionStatus::Finalized((header01.hash(), 0)), + ] + ); + + assert_eq!( + xt1_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02a.hash(), 0)), + TransactionStatus::InBlock((header04b.hash(), 0)), + TransactionStatus::Finalized((header04b.hash(), 0)), + ] + ); + assert_eq!( + xt2_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03a.hash(), 0)), + TransactionStatus::InBlock((header04b.hash(), 1)), + TransactionStatus::Finalized((header04b.hash(), 1)), + ] + ); + assert_eq!( + xt3_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02b.hash(), 0)), + TransactionStatus::Finalized((header02b.hash(), 0)), + ] + ); + assert_eq!( + xt4_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03b.hash(), 0)), + TransactionStatus::Finalized((header03b.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_best_block_after_finalized() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + let header01 = api.push_block(1, vec![], true); + let event = finalized_block_event(&pool, api.genesis_hash(), header01.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + // todo: shall we submit to finalized views? (if it is at the tip of the fork then yes?) + // assert_pool_status!(header01.hash(), &pool, 1, 0); + + let header02 = api.push_block(2, vec![xt0.clone()], true); + + let event = finalized_block_event(&pool, header01.hash(), header02.hash()); + block_on(pool.maintain(event)); + let event = new_best_block_event(&pool, Some(header01.hash()), header02.hash()); + block_on(pool.maintain(event)); + + let xt0_events = block_on(xt0_watcher.collect::>()); + assert_eq!( + xt0_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_best_block_after_finalized2() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 200); + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + let header01 = api.push_block(1, vec![xt0.clone()], true); + + let event = finalized_block_event(&pool, api.genesis_hash(), header01.hash()); + block_on(pool.maintain(event)); + let event = new_best_block_event(&pool, Some(api.genesis_hash()), header01.hash()); + block_on(pool.maintain(event)); + + let xt0_events = block_on(xt0_watcher.collect::>()); + assert_eq!( + xt0_events, + vec![ + TransactionStatus::InBlock((header01.hash(), 0)), + TransactionStatus::Finalized((header01.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_switching_fork_multiple_times_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let header01a = api.push_block(1, vec![xt0.clone()], true); + + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let header01b = api.push_block(1, vec![xt0.clone(), xt1.clone()], true); + + //note: finalized block here must be header01b. + //It is because of how the order in which MultiViewListener is processing tx events and view + //events. tx events from single view are processed first, then view commands are handled. If + //finalization happens in first view reported then no events from others views will be + //processed. + + block_on(pool.maintain(new_best_block_event(&pool, None, header01a.hash()))); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01a.hash()), header01b.hash()))); + block_on(pool.maintain(new_best_block_event(&pool, Some(header01b.hash()), header01a.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header01b.hash()))); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).take(2).collect::>(); + + log::debug!("xt0_status: {:#?}", xt0_status); + log::debug!("xt1_status: {:#?}", xt1_status); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::InBlock((header01a.hash(), 0)), + TransactionStatus::InBlock((header01b.hash(), 0)), + TransactionStatus::Finalized((header01b.hash(), 0)), + ] + ); + + assert_eq!( + xt1_status, + vec![TransactionStatus::Ready, TransactionStatus::InBlock((header01b.hash(), 1)),] + ); +} + +#[test] +fn fatp_watcher_two_blocks_delayed_finalization_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + let xt2 = uxt(Charlie, 200); + + let header01 = api.push_block(1, vec![], true); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let header02 = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); + + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let header03 = api.push_block_with_parent(header02.hash(), vec![xt1.clone()], true); + + let xt2_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + let header04 = api.push_block_with_parent(header03.hash(), vec![xt2.clone()], true); + + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header01.hash()))); + block_on(pool.maintain(new_best_block_event(&pool, None, header04.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header03.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, header03.hash(), header04.hash()))); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).collect::>(); + let xt2_status = futures::executor::block_on_stream(xt2_watcher).collect::>(); + + //todo: double events. + //view for header04 reported InBlock for all xts. + //Then finalization comes for header03. We need to create a view to sent finalization events. + //But in_block are also sent because of pruning - normal process during view creation. + // + //Do not know what solution should be in this case? + // - just jeep two events, + // - block pruning somehow (seems like excessive additional logic not really needed) + // - build view from recent best block? (retracting instead of enacting?) + // - de-dup events in listener (implemented) + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)), + ] + ); + assert_eq!( + xt1_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 0)), + TransactionStatus::Finalized((header03.hash(), 0)), + ] + ); + assert_eq!( + xt2_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header04.hash(), 0)), + TransactionStatus::Finalized((header04.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_delayed_finalization_does_not_retract() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + + let header01 = api.push_block(1, vec![], true); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let header02 = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); + + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let header03 = api.push_block_with_parent(header02.hash(), vec![xt1.clone()], true); + + block_on(pool.maintain(new_best_block_event(&pool, None, header02.hash()))); + block_on(pool.maintain(new_best_block_event(&pool, Some(header02.hash()), header03.hash()))); + + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, header02.hash(), header03.hash()))); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).collect::>(); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)), + ] + ); + assert_eq!( + xt1_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 0)), + TransactionStatus::Finalized((header03.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_best_block_after_finalization_does_not_retract() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + + let header01 = api.push_block(1, vec![], true); + + let xt0_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + let header02 = api.push_block_with_parent(header01.hash(), vec![xt0.clone()], true); + + let xt1_watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let header03 = api.push_block_with_parent(header02.hash(), vec![xt1.clone()], true); + + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header01.hash()))); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header03.hash()))); + block_on(pool.maintain(new_best_block_event(&pool, Some(api.genesis_hash()), header02.hash()))); + + let xt0_status = futures::executor::block_on_stream(xt0_watcher).collect::>(); + let xt1_status = futures::executor::block_on_stream(xt1_watcher).collect::>(); + + log::debug!("xt0_status: {:#?}", xt0_status); + log::debug!("xt1_status: {:#?}", xt1_status); + + assert_eq!( + xt0_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)), + ] + ); + assert_eq!( + xt1_status, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 0)), + TransactionStatus::Finalized((header03.hash(), 0)), + ] + ); +} + +#[test] +fn fatp_watcher_invalid_many_revalidation() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + 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, 201); + let xt2 = uxt(Alice, 202); + let xt3 = uxt(Alice, 203); + let xt4 = uxt(Alice, 204); + + 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()), + pool.submit_and_watch(invalid_hash(), SOURCE, xt3.clone()), + pool.submit_and_watch(invalid_hash(), SOURCE, xt4.clone()), + ]; + + let submissions = block_on(futures::future::join_all(submissions)); + assert_eq!(pool.status_all()[&header01.hash()].ready, 5); + + let mut watchers = submissions.into_iter().map(Result::unwrap).collect::>(); + let xt4_watcher = watchers.remove(4); + let xt3_watcher = watchers.remove(3); + let xt2_watcher = watchers.remove(2); + let xt1_watcher = watchers.remove(1); + let xt0_watcher = watchers.remove(0); + + api.add_invalid(&xt3); + api.add_invalid(&xt4); + + let header02 = api.push_block(2, vec![], true); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header02.hash()))); + + //todo: shall revalidation check finalized (fork's tip) view? + assert_eq!(pool.status_all()[&header02.hash()].ready, 5); + + let header03 = api.push_block(3, vec![xt0.clone(), xt1.clone(), xt2.clone()], true); + block_on(pool.maintain(finalized_block_event(&pool, header02.hash(), header03.hash()))); + + // wait 10 blocks for revalidation + let mut prev_header = header03.clone(); + for n in 4..=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 xt0_events = futures::executor::block_on_stream(xt0_watcher).collect::>(); + let xt1_events = futures::executor::block_on_stream(xt1_watcher).collect::>(); + let xt2_events = futures::executor::block_on_stream(xt2_watcher).collect::>(); + let xt3_events = futures::executor::block_on_stream(xt3_watcher).collect::>(); + let xt4_events = futures::executor::block_on_stream(xt4_watcher).collect::>(); + + log::debug!("xt0_events: {:#?}", xt0_events); + log::debug!("xt1_events: {:#?}", xt1_events); + log::debug!("xt2_events: {:#?}", xt2_events); + log::debug!("xt3_events: {:#?}", xt3_events); + log::debug!("xt4_events: {:#?}", xt4_events); + + assert_eq!( + xt0_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 0)), + TransactionStatus::Finalized((header03.hash(), 0)) + ], + ); + assert_eq!( + xt1_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 1)), + TransactionStatus::Finalized((header03.hash(), 1)) + ], + ); + assert_eq!( + xt2_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header03.hash(), 2)), + TransactionStatus::Finalized((header03.hash(), 2)) + ], + ); + assert_eq!(xt3_events, vec![TransactionStatus::Ready, TransactionStatus::Invalid],); + assert_eq!(xt4_events, vec![TransactionStatus::Ready, TransactionStatus::Invalid],); +} + +#[test] +fn should_not_retain_invalid_hashes_from_retracted() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + let xt = uxt(Alice, 200); + + let header01 = api.push_block(1, vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + let watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt.clone())).unwrap(); + + let header02a = api.push_block_with_parent(header01.hash(), vec![xt.clone()], true); + + block_on(pool.maintain(new_best_block_event(&pool, Some(header01.hash()), header02a.hash()))); + assert_eq!(pool.status_all()[&header02a.hash()].ready, 0); + + api.add_invalid(&xt); + let header02b = api.push_block_with_parent(header01.hash(), vec![], true); + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02b.hash()))); + + // wait 10 blocks for revalidation + let mut prev_header = header02b.clone(); + for _ in 3..=11 { + let header = api.push_block_with_parent(prev_header.hash(), vec![], true); + let event = finalized_block_event(&pool, prev_header.hash(), header.hash()); + block_on(pool.maintain(event)); + prev_header = header; + } + + assert_eq!( + futures::executor::block_on_stream(watcher).collect::>(), + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02a.hash(), 0)), + TransactionStatus::Invalid + ], + ); + + //todo: shall revalidation check finalized (fork's tip) view? + assert_eq!(pool.status_all()[&prev_header.hash()].ready, 0); +} + +#[test] +fn should_revalidate_during_maintenance() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + let xt1 = uxt(Alice, 200); + let xt2 = uxt(Alice, 201); + + let header01 = api.push_block(1, vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + + block_on(pool.submit_one(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let watcher = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + assert_eq!(pool.status_all()[&header01.hash()].ready, 2); + assert_eq!(api.validation_requests().len(), 2); + + let header02 = api.push_block(2, vec![xt1.clone()], true); + api.add_invalid(&xt2); + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02.hash()))); + + //todo: shall revalidation check finalized (fork's tip) view? + assert_eq!(pool.status_all()[&header02.hash()].ready, 1); + + // wait 10 blocks for revalidation + let mut prev_header = header02.clone(); + for _ in 3..=11 { + let header = api.push_block_with_parent(prev_header.hash(), vec![], true); + let event = finalized_block_event(&pool, prev_header.hash(), header.hash()); + block_on(pool.maintain(event)); + prev_header = header; + } + + assert_eq!( + futures::executor::block_on_stream(watcher).collect::>(), + vec![TransactionStatus::Ready, TransactionStatus::Invalid], + ); +} + +#[test] +fn fatp_transactions_purging_stale_on_finalization_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt1 = uxt(Alice, 200); + let xt2 = uxt(Alice, 201); + let xt3 = uxt(Alice, 202); + + let header01 = api.push_block(1, vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + + let watcher1 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let watcher2 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + + assert_eq!(api.validation_requests().len(), 3); + assert_eq!(pool.status_all()[&header01.hash()].ready, 3); + assert_eq!(pool.mempool_len(), (1, 2)); + + let header02 = api.push_block(2, vec![xt1.clone(), xt2.clone(), xt3.clone()], true); + api.set_nonce(header02.hash(), Alice.into(), 203); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header02.hash()))); + + assert_eq!(pool.status_all()[&header02.hash()].ready, 0); + assert_eq!(pool.mempool_len(), (0, 0)); + + let xt1_events = futures::executor::block_on_stream(watcher1).collect::>(); + let xt2_events = futures::executor::block_on_stream(watcher2).collect::>(); + assert_eq!( + xt1_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 0)), + TransactionStatus::Finalized((header02.hash(), 0)) + ], + ); + assert_eq!( + xt2_events, + vec![ + TransactionStatus::Ready, + TransactionStatus::InBlock((header02.hash(), 1)), + TransactionStatus::Finalized((header02.hash(), 1)) + ], + ); +} + +#[test] +fn fatp_transactions_purging_invalid_on_finalization_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt1 = uxt(Alice, 200); + let xt2 = uxt(Alice, 201); + let xt3 = uxt(Alice, 202); + + let header01 = api.push_block(1, vec![], true); + block_on(pool.maintain(new_best_block_event(&pool, None, header01.hash()))); + + let watcher1 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let watcher2 = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt3.clone())).unwrap(); + + assert_eq!(api.validation_requests().len(), 3); + assert_eq!(pool.status_all()[&header01.hash()].ready, 3); + assert_eq!(pool.mempool_len(), (1, 2)); + + let header02 = api.push_block(2, vec![], true); + api.add_invalid(&xt1); + api.add_invalid(&xt2); + api.add_invalid(&xt3); + block_on(pool.maintain(finalized_block_event(&pool, header01.hash(), header02.hash()))); + + // wait 10 blocks for revalidation + let mut prev_header = header02; + for n in 3..=13 { + 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; + } + + //todo: should it work at all? (it requires better revalidation: mempool keeping validated txs) + //additionally it also requires revalidation of finalized view. + // assert_eq!(pool.status_all()[&header02.hash()].ready, 0); + assert_eq!(pool.mempool_len(), (0, 0)); + + let xt1_events = futures::executor::block_on_stream(watcher1).collect::>(); + let xt2_events = futures::executor::block_on_stream(watcher2).collect::>(); + assert_eq!(xt1_events, vec![TransactionStatus::Ready, TransactionStatus::Invalid]); + assert_eq!(xt2_events, vec![TransactionStatus::Ready, TransactionStatus::Invalid]); +} + +#[test] +fn import_sink_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let genesis = api.genesis_hash(); + let header01a = api.push_block(1, vec![], true); + let header01b = api.push_block(1, vec![], true); + + let import_stream = pool.import_notification_stream(); + + let event = new_best_block_event(&pool, None, header01a.hash()); + block_on(pool.maintain(event)); + + let event = new_best_block_event(&pool, None, header01b.hash()); + block_on(pool.maintain(event)); + + api.set_nonce(header01b.hash(), Alice.into(), 202); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(genesis, SOURCE, xt0.clone()), + pool.submit_one(genesis, SOURCE, xt1.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + assert_pool_status!(header01a.hash(), &pool, 1, 1); + assert_pool_status!(header01b.hash(), &pool, 1, 0); + + let import_events = + futures::executor::block_on_stream(import_stream).take(2).collect::>(); + + let expected_import_events = vec![api.hash_and_length(&xt0).0, api.hash_and_length(&xt1).0]; + assert!(import_events.iter().all(|v| expected_import_events.contains(v))); +} + +#[test] +fn import_sink_works2() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let genesis = api.genesis_hash(); + let header01a = api.push_block(1, vec![], true); + let header01b = api.push_block(1, vec![], true); + + let import_stream = pool.import_notification_stream(); + + let event = new_best_block_event(&pool, None, header01a.hash()); + block_on(pool.maintain(event)); + + let event = new_best_block_event(&pool, None, header01b.hash()); + block_on(pool.maintain(event)); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(genesis, SOURCE, xt0.clone()), + pool.submit_one(genesis, SOURCE, xt1.clone()), + ]; + + block_on(futures::future::join_all(submissions)); + + assert_pool_status!(header01a.hash(), &pool, 1, 1); + assert_pool_status!(header01b.hash(), &pool, 1, 1); + + let import_events = + futures::executor::block_on_stream(import_stream).take(1).collect::>(); + + let expected_import_events = vec![api.hash_and_length(&xt0).0]; + assert_eq!(import_events, expected_import_events); +} + +#[test] +fn import_sink_works3() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let import_stream = pool.import_notification_stream(); + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(genesis, SOURCE, xt0.clone()), + pool.submit_one(genesis, SOURCE, xt1.clone()), + ]; + + let x = block_on(futures::future::join_all(submissions)); + + let header01a = api.push_block(1, vec![], true); + let header01b = api.push_block(1, vec![], true); + + let event = new_best_block_event(&pool, None, header01a.hash()); + block_on(pool.maintain(event)); + + let event = new_best_block_event(&pool, None, header01b.hash()); + block_on(pool.maintain(event)); + + assert_pool_status!(header01a.hash(), &pool, 1, 1); + assert_pool_status!(header01b.hash(), &pool, 1, 1); + + log::debug!("xxx {x:#?}"); + + let import_events = + futures::executor::block_on_stream(import_stream).take(1).collect::>(); + + let expected_import_events = vec![api.hash_and_length(&xt0).0]; + assert_eq!(import_events, expected_import_events); +} + +#[test] +fn fatp_avoid_stuck_transaction() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Alice, 202); + let xt3 = uxt(Alice, 203); + let xt4 = uxt(Alice, 204); + let xt4i = uxt(Alice, 204); + let xt4i_watcher = + block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt4i.clone())).unwrap(); + + assert_eq!(pool.mempool_len(), (0, 1)); + + let header01 = api.push_block(1, vec![xt0], true); + api.set_nonce(header01.hash(), Alice.into(), 201); + let header02 = api.push_block(2, vec![xt1], true); + api.set_nonce(header02.hash(), Alice.into(), 202); + let header03 = api.push_block(3, vec![xt2], true); + api.set_nonce(header03.hash(), Alice.into(), 203); + + let header04 = api.push_block(4, vec![], true); + api.set_nonce(header04.hash(), Alice.into(), 203); + + let header05 = api.push_block(5, vec![], true); + api.set_nonce(header05.hash(), Alice.into(), 203); + + let event = new_best_block_event(&pool, None, header05.hash()); + block_on(pool.maintain(event)); + + let event = finalized_block_event(&pool, api.genesis_hash(), header03.hash()); + block_on(pool.maintain(event)); + + assert_pool_status!(header05.hash(), &pool, 0, 1); + + let header06 = api.push_block(6, vec![xt3, xt4], true); + api.set_nonce(header06.hash(), Alice.into(), 205); + let event = new_best_block_event(&pool, None, header06.hash()); + block_on(pool.maintain(event)); + + 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 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!(pool.mempool_len(), (0, 0)); +} + +#[test] +fn fatp_future_is_pruned_by_conflicting_tags() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Alice, 202); + let xt2i = uxt(Alice, 202); + log::debug!("xt0: {:#?}", api.hash_and_length(&xt0).0); + log::debug!("xt1: {:#?}", api.hash_and_length(&xt1).0); + log::debug!("xt2: {:#?}", api.hash_and_length(&xt2).0); + log::debug!("xt2i: {:#?}", api.hash_and_length(&xt2i).0); + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2i.clone())).unwrap(); + + assert_eq!(pool.mempool_len(), (0, 1)); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01.hash(), &pool, 0, 1); + + let header02 = api.push_block(2, vec![xt0, xt1, xt2], true); + api.set_nonce(header02.hash(), Alice.into(), 203); + + let event = new_best_block_event(&pool, None, header02.hash()); + block_on(pool.maintain(event)); + + assert_pool_status!(header02.hash(), &pool, 0, 0); +} + +#[test] +fn fatp_dangling_ready_gets_revalidated() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt2 = uxt(Alice, 202); + log::debug!("xt2: {:#?}", api.hash_and_length(&xt2).0); + + let header01 = api.push_block(1, vec![], true); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01.hash(), &pool, 0, 0); + + let header02a = api.push_block_with_parent(header01.hash(), vec![], true); + api.set_nonce(header02a.hash(), Alice.into(), 202); + let event = new_best_block_event(&pool, Some(header01.hash()), header02a.hash()); + block_on(pool.maintain(event)); + + // send xt2 - it will become ready on block 02a. + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + assert_pool_status!(header02a.hash(), &pool, 1, 0); + assert_eq!(pool.mempool_len(), (0, 1)); + + //xt2 is still ready: view was just cloned (revalidation executed in background) + let header02b = api.push_block_with_parent(header01.hash(), vec![], true); + let event = new_best_block_event(&pool, Some(header02a.hash()), header02b.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header02b.hash(), &pool, 1, 0); + + //xt2 is now future - view revalidation worked. + let header03b = api.push_block_with_parent(header02b.hash(), vec![], true); + let event = new_best_block_event(&pool, Some(header02b.hash()), header03b.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header03b.hash(), &pool, 0, 1); +} + +#[test] +fn fatp_ready_txs_are_provided_in_valid_order() { + // this test checks if recently_pruned tags are cleared for views cloned from retracted path + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Alice, 202); + log::debug!("xt0: {:#?}", api.hash_and_length(&xt0).0); + log::debug!("xt1: {:#?}", api.hash_and_length(&xt1).0); + log::debug!("xt2: {:#?}", api.hash_and_length(&xt2).0); + + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt1.clone())).unwrap(); + let _ = block_on(pool.submit_and_watch(invalid_hash(), SOURCE, xt0.clone())).unwrap(); + + let header01 = api.push_block(1, vec![xt0], true); + api.set_nonce(header01.hash(), Alice.into(), 201); + let event = new_best_block_event(&pool, None, header01.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01.hash(), &pool, 2, 0); + + let header02a = + api.push_block_with_parent(header01.hash(), vec![xt1.clone(), xt2.clone()], true); + api.set_nonce(header02a.hash(), Alice.into(), 203); + let event = new_best_block_event(&pool, Some(header01.hash()), header02a.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header02a.hash(), &pool, 0, 0); + + let header02b = api.push_block_with_parent(header01.hash(), vec![], true); + api.set_nonce(header02b.hash(), Alice.into(), 201); + let event = new_best_block_event(&pool, Some(header02a.hash()), header02b.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header02b.hash(), &pool, 2, 0); + assert_ready_iterator!(header02b.hash(), pool, [xt1, xt2]); +} + +//todo: add test: check len of filter after finalization (!) +//todo: broadcasted test? + +#[test] +fn fatp_ready_light_empty_on_unmaintained_fork() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + + let header01a = api.push_block_with_parent(genesis, vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(genesis), header01a.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01a.hash(), &pool, 0, 0); + + let header01b = api.push_block_with_parent(genesis, vec![xt1.clone()], true); + + let mut ready_iterator = pool.ready_at_light(header01b.hash()).now_or_never().unwrap(); + assert!(ready_iterator.next().is_none()); +} + +#[test] +fn fatp_ready_light_misc_scenarios_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + let xt2 = uxt(Charlie, 200); + + //fork A + let header01a = api.push_block_with_parent(genesis, vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(genesis), header01a.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01a.hash(), &pool, 0, 0); + + //fork B + let header01b = api.push_block_with_parent(genesis, vec![xt1.clone()], true); + let event = new_best_block_event(&pool, Some(header01a.hash()), header01b.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01b.hash(), &pool, 1, 0); + + //new block at fork B + let header02b = api.push_block_with_parent(header01b.hash(), vec![xt1.clone()], true); + + // test 1: + //ready light returns just txs from view @header01b (which contains retracted xt0) + let mut ready_iterator = pool.ready_at_light(header02b.hash()).now_or_never().unwrap(); + let ready01 = ready_iterator.next(); + assert_eq!(ready01.unwrap().hash, api.hash_and_length(&xt0).0); + assert!(ready_iterator.next().is_none()); + + // test 2: + // submit new transaction to all views + block_on(pool.submit_one(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + + //new block at fork A, not yet notified to pool + let header02a = api.push_block_with_parent(header01a.hash(), vec![], true); + + //ready light returns just txs from view @header01a (which contains newly submitted xt2) + let mut ready_iterator = pool.ready_at_light(header02a.hash()).now_or_never().unwrap(); + let ready01 = ready_iterator.next(); + assert_eq!(ready01.unwrap().hash, api.hash_and_length(&xt2).0); + assert!(ready_iterator.next().is_none()); + + //test 3: + let mut ready_iterator = pool.ready_at_light(header02b.hash()).now_or_never().unwrap(); + let ready01 = ready_iterator.next(); + assert_eq!(ready01.unwrap().hash, api.hash_and_length(&xt0).0); + let ready02 = ready_iterator.next(); + assert_eq!(ready02.unwrap().hash, api.hash_and_length(&xt2).0); + assert!(ready_iterator.next().is_none()); + + //test 4: + //new block at fork B, not yet notified to pool + let header03b = + api.push_block_with_parent(header02b.hash(), vec![xt0.clone(), xt2.clone()], true); + //ready light @header03b will be empty: as new block contains xt0/xt2 + let mut ready_iterator = pool.ready_at_light(header03b.hash()).now_or_never().unwrap(); + assert!(ready_iterator.next().is_none()); +} + +#[test] +fn fatp_ready_light_long_fork_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + api.set_nonce(api.genesis_hash(), Dave.into(), 200); + api.set_nonce(api.genesis_hash(), Eve.into(), 200); + + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + let xt2 = uxt(Charlie, 200); + let xt3 = uxt(Dave, 200); + let xt4 = uxt(Eve, 200); + + let submissions = vec![pool.submit_at( + genesis, + SOURCE, + vec![xt0.clone(), xt1.clone(), xt2.clone(), xt3.clone(), xt4.clone()], + )]; + let results = block_on(futures::future::join_all(submissions)); + assert!(results.iter().all(Result::is_ok)); + + let header01 = api.push_block_with_parent(genesis, vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(genesis), header01.hash()); + block_on(pool.maintain(event)); + + let header02 = api.push_block_with_parent(header01.hash(), vec![xt1.clone()], true); + let header03 = api.push_block_with_parent(header02.hash(), vec![xt2.clone()], true); + let header04 = api.push_block_with_parent(header03.hash(), vec![xt3.clone()], true); + + let mut ready_iterator = pool.ready_at_light(header04.hash()).now_or_never().unwrap(); + let ready01 = ready_iterator.next(); + assert_eq!(ready01.unwrap().hash, api.hash_and_length(&xt4).0); + assert!(ready_iterator.next().is_none()); +} + +#[test] +fn fatp_ready_light_long_fork_retracted_works() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + api.set_nonce(api.genesis_hash(), Dave.into(), 200); + api.set_nonce(api.genesis_hash(), Eve.into(), 200); + + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + let xt2 = uxt(Charlie, 200); + let xt3 = uxt(Dave, 200); + let xt4 = uxt(Eve, 200); + + let submissions = vec![pool.submit_at( + genesis, + SOURCE, + vec![xt0.clone(), xt1.clone(), xt2.clone(), xt3.clone()], + )]; + let results = block_on(futures::future::join_all(submissions)); + assert!(results.iter().all(|r| { r.is_ok() })); + + let header01a = api.push_block_with_parent(genesis, vec![xt4.clone()], true); + let event = new_best_block_event(&pool, Some(genesis), header01a.hash()); + block_on(pool.maintain(event)); + + let header01b = api.push_block_with_parent(genesis, vec![xt0.clone()], true); + let header02b = api.push_block_with_parent(header01b.hash(), vec![xt1.clone()], true); + let header03b = api.push_block_with_parent(header02b.hash(), vec![xt2.clone()], true); + + let mut ready_iterator = pool.ready_at_light(header03b.hash()).now_or_never().unwrap(); + assert!(ready_iterator.next().is_none()); + + let event = new_best_block_event(&pool, Some(header01a.hash()), header01b.hash()); + block_on(pool.maintain(event)); + + let mut ready_iterator = pool.ready_at_light(header03b.hash()).now_or_never().unwrap(); + let ready01 = ready_iterator.next(); + assert_eq!(ready01.unwrap().hash, api.hash_and_length(&xt3).0); + let ready02 = ready_iterator.next(); + assert_eq!(ready02.unwrap().hash, api.hash_and_length(&xt4).0); + assert!(ready_iterator.next().is_none()); +} + +#[test] +fn fatp_ready_at_with_timeout_works_for_misc_scenarios() { + sp_tracing::try_init_simple(); + + let (pool, api, _) = pool(); + api.set_nonce(api.genesis_hash(), Bob.into(), 200); + api.set_nonce(api.genesis_hash(), Charlie.into(), 200); + let genesis = api.genesis_hash(); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Bob, 200); + + let header01a = api.push_block_with_parent(genesis, vec![xt0.clone()], true); + let event = new_best_block_event(&pool, Some(genesis), header01a.hash()); + block_on(pool.maintain(event)); + assert_pool_status!(header01a.hash(), &pool, 0, 0); + + let header01b = api.push_block_with_parent(genesis, vec![xt1.clone()], true); + + let mut ready_at_future = + pool.ready_at_with_timeout(header01b.hash(), Duration::from_secs(36000)); + + let noop_waker = futures::task::noop_waker(); + let mut context = futures::task::Context::from_waker(&noop_waker); + + if ready_at_future.poll_unpin(&mut context).is_ready() { + panic!("Ready set should not be ready before maintenance on block update!"); + } + + let event = new_best_block_event(&pool, Some(header01a.hash()), header01b.hash()); + block_on(pool.maintain(event)); + + // ready should now be triggered: + let mut ready_at = ready_at_future.now_or_never().unwrap(); + assert_eq!(ready_at.next().unwrap().hash, api.hash_and_length(&xt0).0); + assert!(ready_at.next().is_none()); + + let header02a = api.push_block_with_parent(header01a.hash(), vec![], true); + let xt2 = uxt(Charlie, 200); + block_on(pool.submit_one(invalid_hash(), SOURCE, xt2.clone())).unwrap(); + + // ready light should now be triggered: + let mut ready_at2 = block_on(pool.ready_at_with_timeout(header02a.hash(), Duration::ZERO)); + assert_eq!(ready_at2.next().unwrap().hash, api.hash_and_length(&xt2).0); + assert!(ready_at2.next().is_none()); +} diff --git a/substrate/client/transaction-pool/tests/fatp_common/mod.rs b/substrate/client/transaction-pool/tests/fatp_common/mod.rs new file mode 100644 index 000000000000..15f2b7f79c14 --- /dev/null +++ b/substrate/client/transaction-pool/tests/fatp_common/mod.rs @@ -0,0 +1,285 @@ +// 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 for fork-aware transaction pool. + +use sc_transaction_pool::{ChainApi, PoolLimit}; +use sc_transaction_pool_api::ChainEvent; +use sp_runtime::transaction_validity::TransactionSource; +use std::sync::Arc; +use substrate_test_runtime_client::{ + runtime::{Block, Hash, Header}, + AccountKeyring::*, +}; +use substrate_test_runtime_transaction_pool::{uxt, TestApi}; +pub const LOG_TARGET: &str = "txpool"; + +use sc_transaction_pool::ForkAwareTxPool; + +pub fn invalid_hash() -> Hash { + Default::default() +} + +pub fn new_best_block_event( + pool: &ForkAwareTxPool, + from: Option, + to: Hash, +) -> ChainEvent { + ChainEvent::NewBestBlock { + hash: to, + tree_route: from.map(|from| { + // note: real tree route in NewBestBlock event does not contain 'to' block. + Arc::from( + pool.api() + .tree_route(from, pool.api().block_header(to).unwrap().unwrap().parent_hash) + .expect("Tree route exists"), + ) + }), + } +} + +pub fn finalized_block_event( + pool: &ForkAwareTxPool, + from: Hash, + to: Hash, +) -> ChainEvent { + let t = pool.api().tree_route(from, to).expect("Tree route exists"); + + let e = t.enacted().iter().map(|h| h.hash).collect::>(); + ChainEvent::Finalized { hash: to, tree_route: Arc::from(&e[0..e.len() - 1]) } +} + +pub struct TestPoolBuilder { + api: Option>, + use_default_limits: bool, + ready_limits: sc_transaction_pool::PoolLimit, + future_limits: sc_transaction_pool::PoolLimit, + mempool_max_transactions_count: usize, +} + +impl Default for TestPoolBuilder { + fn default() -> Self { + Self { + api: None, + use_default_limits: true, + ready_limits: PoolLimit { count: 8192, total_bytes: 20 * 1024 * 1024 }, + future_limits: PoolLimit { count: 512, total_bytes: 1 * 1024 * 1024 }, + mempool_max_transactions_count: usize::MAX, + } + } +} + +impl TestPoolBuilder { + pub fn new() -> Self { + Self::default() + } + + pub fn with_api(mut self, api: Arc) -> Self { + self.api = Some(api); + self + } + + pub fn with_mempool_count_limit(mut self, mempool_count_limit: usize) -> Self { + self.mempool_max_transactions_count = mempool_count_limit; + self.use_default_limits = false; + self + } + + pub fn with_ready_count(mut self, ready_count: usize) -> Self { + self.ready_limits.count = ready_count; + self.use_default_limits = false; + self + } + + pub fn with_ready_bytes_size(mut self, ready_bytes_size: usize) -> Self { + self.ready_limits.total_bytes = ready_bytes_size; + self.use_default_limits = false; + self + } + + pub fn with_future_count(mut self, future_count: usize) -> Self { + self.future_limits.count = future_count; + self.use_default_limits = false; + self + } + + pub fn with_future_bytes_size(mut self, future_bytes_size: usize) -> Self { + self.future_limits.total_bytes = future_bytes_size; + self.use_default_limits = false; + self + } + + pub fn build( + self, + ) -> (ForkAwareTxPool, Arc, futures::executor::ThreadPool) { + let api = self + .api + .unwrap_or(Arc::from(TestApi::with_alice_nonce(200).enable_stale_check())); + + let genesis_hash = api + .chain() + .read() + .block_by_number + .get(&0) + .map(|blocks| blocks[0].0.header.hash()) + .expect("there is block 0. qed"); + + let (pool, txpool_task) = if self.use_default_limits { + ForkAwareTxPool::new_test(api.clone(), genesis_hash, genesis_hash) + } else { + ForkAwareTxPool::new_test_with_limits( + api.clone(), + genesis_hash, + genesis_hash, + self.ready_limits, + self.future_limits, + self.mempool_max_transactions_count, + ) + }; + + let thread_pool = futures::executor::ThreadPool::new().unwrap(); + thread_pool.spawn_ok(txpool_task); + + (pool, api, thread_pool) + } +} + +pub fn pool_with_api( + test_api: Arc, +) -> (ForkAwareTxPool, futures::executor::ThreadPool) { + let builder = TestPoolBuilder::new(); + let (pool, _, threadpool) = builder.with_api(test_api).build(); + (pool, threadpool) +} + +pub fn pool() -> (ForkAwareTxPool, Arc, futures::executor::ThreadPool) { + let builder = TestPoolBuilder::new(); + builder.build() +} + +#[macro_export] +macro_rules! assert_pool_status { + ($hash:expr, $pool:expr, $ready:expr, $future:expr) => { + { + log::debug!(target:LOG_TARGET, "stats: {:#?}", $pool.status_all()); + let status = &$pool.status_all()[&$hash]; + assert_eq!(status.ready, $ready, "ready"); + assert_eq!(status.future, $future, "future"); + } + } +} + +#[macro_export] +macro_rules! assert_ready_iterator { + ($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 output: Vec<_> = ready_iterator.collect(); + log::debug!(target:LOG_TARGET, "expected: {:#?}", expected); + log::debug!(target:LOG_TARGET, "output: {:#?}", output); + assert_eq!(expected.len(), output.len()); + assert!( + output.iter().zip(expected.iter()).all(|(o,e)| { + o.hash == *e + }) + ); + }}; +} + +pub const SOURCE: TransactionSource = TransactionSource::External; + +#[cfg(test)] +pub mod test_chain_with_forks { + use super::*; + + pub fn chain( + include_xts: Option<&dyn Fn(usize, usize) -> bool>, + ) -> (Arc, Vec>) { + // Fork layout: + // + // (fork 0) + // F01 - F02 - F03 - F04 - F05 | Alice nonce increasing, alice's txs + // / + // F00 + // \ (fork 1) + // F11 - F12 - F13 - F14 - F15 | Bob nonce increasing, Bob's txs + // + // + // e.g. F03 contains uxt(Alice, 202), nonces: Alice = 203, Bob = 200 + // F12 contains uxt(Bob, 201), nonces: Alice = 200, Bob = 202 + + let api = Arc::from(TestApi::empty().enable_stale_check()); + + let genesis = api.genesis_hash(); + + let mut forks = vec![Vec::with_capacity(6), Vec::with_capacity(6)]; + let accounts = vec![Alice, Bob]; + accounts.iter().for_each(|a| api.set_nonce(genesis, (*a).into(), 200)); + + for fork in 0..2 { + let account = accounts[fork]; + forks[fork].push(api.block_header(genesis).unwrap().unwrap()); + let mut parent = genesis; + for block in 1..6 { + let xts = if include_xts.map_or(true, |v| v(fork, block)) { + log::debug!("{},{} -> add", fork, block); + vec![uxt(account, (200 + block - 1) as u64)] + } else { + log::debug!("{},{} -> skip", fork, block); + vec![] + }; + let header = api.push_block_with_parent(parent, xts, true); + parent = header.hash(); + api.set_nonce(header.hash(), account.into(), (200 + block) as u64); + forks[fork].push(header); + } + } + + (api, forks) + } + + pub fn print_block(api: Arc, hash: Hash) { + let accounts = vec![Alice.into(), Bob.into()]; + let header = api.block_header(hash).unwrap().unwrap(); + + let nonces = accounts + .iter() + .map(|a| api.chain().read().nonces.get(&hash).unwrap().get(a).map(Clone::clone)) + .collect::>(); + log::debug!( + "number: {:?} hash: {:?}, parent: {:?}, nonces:{:?}", + header.number, + header.hash(), + header.parent_hash, + nonces + ); + } + + #[test] + fn test_chain_works() { + sp_tracing::try_init_simple(); + let (api, f) = chain(None); + log::debug!("forks: {f:#?}"); + f[0].iter().for_each(|h| print_block(api.clone(), h.hash())); + f[1].iter().for_each(|h| print_block(api.clone(), h.hash())); + let tr = api.tree_route(f[0][5].hash(), f[1][5].hash()).unwrap(); + log::debug!("{:#?}", tr); + log::debug!("e:{:#?}", tr.enacted()); + log::debug!("r:{:#?}", tr.retracted()); + } +} diff --git a/substrate/client/transaction-pool/tests/fatp_limits.rs b/substrate/client/transaction-pool/tests/fatp_limits.rs new file mode 100644 index 000000000000..03792fd89dfa --- /dev/null +++ b/substrate/client/transaction-pool/tests/fatp_limits.rs @@ -0,0 +1,643 @@ +// 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 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, +}; +use futures::{executor::block_on, FutureExt}; +use sc_transaction_pool::ChainApi; +use sc_transaction_pool_api::{ + error::Error as TxPoolError, MaintainedTransactionPool, TransactionPool, TransactionStatus, +}; +use std::thread::sleep; +use substrate_test_runtime_client::AccountKeyring::*; +use substrate_test_runtime_transaction_pool::uxt; + +#[test] +fn fatp_limits_no_views_mempool_count() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(2).build(); + + let header = api.push_block(1, vec![], true); + + let xt0 = uxt(Alice, 200); + let xt1 = uxt(Alice, 201); + let xt2 = uxt(Alice, 202); + + let submissions = vec![ + pool.submit_one(header.hash(), SOURCE, xt0.clone()), + pool.submit_one(header.hash(), SOURCE, xt1.clone()), + pool.submit_one(header.hash(), SOURCE, xt2.clone()), + ]; + + let results = block_on(futures::future::join_all(submissions)); + let mut results = results.iter(); + + assert!(results.next().unwrap().is_ok()); + assert!(results.next().unwrap().is_ok()); + assert!(matches!( + results.next().unwrap().as_ref().unwrap_err().0, + TxPoolError::ImmediatelyDropped + )); +} + +#[test] +fn fatp_limits_ready_count_works() { + 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)); + + //note: we need Charlie to be first as the oldest is removed. + //For 3x alice, all tree would be removed. + //(alice,bob,charlie would work too) + let xt0 = uxt(Charlie, 500); + let xt1 = uxt(Alice, 200); + let xt2 = uxt(Alice, 201); + + 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, 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, 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, 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(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.with_mempool_count_limit(3).with_future_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(Alice, 200); + + let xt1 = uxt(Charlie, 501); + let xt2 = uxt(Alice, 201); + let xt3 = uxt(Alice, 202); + + 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(); + + //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)); + + assert_pool_status!(header02.hash(), &pool, 2, 0); + assert_eq!(pool.mempool_len().0, 2); +} + +#[test] +fn fatp_limits_watcher_mempool_doesnt_prevent_dropping() { + 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(), 400); + + 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, 400); + let xt1 = uxt(Bob, 300); + let xt2 = uxt(Alice, 200); + + 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(2).collect::>(); + log::debug!("xt0_status: {:#?}", xt0_status); + 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]); + + let xt2_status = futures::executor::block_on_stream(xt2_watcher).take(1).collect::>(); + log::debug!("xt2_status: {:#?}", xt2_status); + + assert_eq!(xt2_status, vec![TransactionStatus::Ready]); +} + +#[test] +fn fatp_limits_watcher_non_intial_view_drops_transaction() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.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); + + 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(Dave, 500); + let xt1 = uxt(Charlie, 400); + let xt2 = uxt(Bob, 300); + + 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, [xt1, xt2]); + + 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]); +} + +#[test] +fn fatp_limits_watcher_finalized_transaction_frees_ready_space() { + sp_tracing::try_init_simple(); + + let builder = TestPoolBuilder::new(); + let (pool, api, _) = builder.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); + + 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(Dave, 500); + let xt1 = uxt(Charlie, 400); + let xt2 = uxt(Bob, 300); + + 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 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]); +} + +#[test] +fn fatp_limits_watcher_view_can_drop_transcation() { + 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(), 400); + api.set_nonce(api.genesis_hash(), Dave.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(Dave, 500); + let xt1 = uxt(Charlie, 400); + let xt2 = uxt(Bob, 300); + let xt3 = uxt(Alice, 200); + + 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![], true); + block_on(pool.maintain(finalized_block_event(&pool, api.genesis_hash(), header02.hash()))); + + 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 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::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 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); +} diff --git a/substrate/client/transaction-pool/tests/pool.rs b/substrate/client/transaction-pool/tests/pool.rs index 6d70b6ce67ec..ed0fd7d4e655 100644 --- a/substrate/client/transaction-pool/tests/pool.rs +++ b/substrate/client/transaction-pool/tests/pool.rs @@ -85,12 +85,13 @@ const SOURCE: TransactionSource = TransactionSource::External; #[test] fn submission_should_work() { let (pool, api) = pool(); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + .unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, vec![209]); } @@ -98,13 +99,15 @@ fn submission_should_work() { #[test] fn multiple_submission_should_work() { let (pool, api) = pool(); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + .unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 210).into())) + .unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, vec![209, 210]); } @@ -113,12 +116,14 @@ 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_from_number(0), SOURCE, uxt(Alice, 208))).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 208).into())) + .unwrap(); + log::debug!("-> {:?}", pool.validated_pool().status()); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, Vec::::new()); } @@ -127,19 +132,21 @@ fn early_nonce_should_be_culled() { fn late_nonce_should_be_queued() { let (pool, api) = pool(); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 210).into())) + .unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, Vec::::new()); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + .unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, vec![209, 210]); } @@ -148,24 +155,25 @@ 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_from_number(0), SOURCE, uxt(Alice, 209))).unwrap(); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt(Alice, 210))).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 209).into())) + .unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt(Alice, 210).into())) + .unwrap(); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, vec![209, 210]); pool.validated_pool().api().push_block(1, Vec::new(), true); - block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![209]], vec![hash209])) - .expect("Prune tags"); + block_on(pool.prune_tags(&api.expect_hash_and_number(1), vec![vec![209]], vec![hash209])); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, vec![210]); } @@ -173,22 +181,22 @@ fn prune_tags_should_work() { #[test] fn should_ban_invalid_transactions() { let (pool, api) = pool(); - let uxt = uxt(Alice, 209); + let uxt = Arc::from(uxt(Alice, 209)); let hash = - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.clone())).unwrap(); pool.validated_pool().remove_invalid(&[hash]); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap_err(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.clone())).unwrap_err(); // when let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, Vec::::new()); // then - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, uxt.clone())).unwrap_err(); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, uxt.clone())).unwrap_err(); } #[test] @@ -209,47 +217,56 @@ fn only_prune_on_new_best() { #[test] fn should_correctly_prune_transactions_providing_more_than_one_tag() { + sp_tracing::try_init_simple(); let api = Arc::new(TestApi::with_alice_nonce(209)); api.set_valid_modifier(Box::new(|v: &mut ValidTransaction| { v.provides.push(vec![155]); })); let pool = Pool::new(Default::default(), true.into(), api.clone()); - let xt = uxt(Alice, 209); - block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt.clone())) + let xt0 = Arc::from(uxt(Alice, 209)); + block_on(pool.submit_one(&api.expect_hash_and_number(0), SOURCE, xt0.clone())) .expect("1. Imported"); assert_eq!(pool.validated_pool().status().ready, 1); + assert_eq!(api.validation_requests().len(), 1); // remove the transaction that just got imported. api.increment_nonce(Alice.into()); api.push_block(1, Vec::new(), true); - block_on(pool.prune_tags(api.expect_hash_from_number(1), vec![vec![209]], vec![])) - .expect("1. Pruned"); + block_on(pool.prune_tags(&api.expect_hash_and_number(1), vec![vec![209]], vec![])); + assert_eq!(api.validation_requests().len(), 2); assert_eq!(pool.validated_pool().status().ready, 0); - // it's re-imported to future + // it's re-imported to future, API does not support stale - xt0 becomes future assert_eq!(pool.validated_pool().status().future, 1); // so now let's insert another transaction that also provides the 155 api.increment_nonce(Alice.into()); api.push_block(2, Vec::new(), true); - let xt = uxt(Alice, 211); - block_on(pool.submit_one(api.expect_hash_from_number(2), SOURCE, xt.clone())) + let xt1 = uxt(Alice, 211); + block_on(pool.submit_one(&api.expect_hash_and_number(2), SOURCE, xt1.clone().into())) .expect("2. Imported"); + assert_eq!(api.validation_requests().len(), 3); assert_eq!(pool.validated_pool().status().ready, 1); assert_eq!(pool.validated_pool().status().future, 1); let pending: Vec<_> = pool .validated_pool() .ready() - .map(|a| TransferData::try_from(&a.data).unwrap().nonce) + .map(|a| TransferData::try_from(&*a.data).unwrap().nonce) .collect(); assert_eq!(pending, vec![211]); // prune it and make sure the pool is empty api.increment_nonce(Alice.into()); api.push_block(3, Vec::new(), true); - block_on(pool.prune_tags(api.expect_hash_from_number(3), vec![vec![155]], vec![])) - .expect("2. Pruned"); + block_on(pool.prune_tags(&api.expect_hash_and_number(3), vec![vec![155]], vec![])); + assert_eq!(api.validation_requests().len(), 4); + //xt0 was future, it failed (bc of 155 tag conflict) and was removed assert_eq!(pool.validated_pool().status().ready, 0); - assert_eq!(pool.validated_pool().status().future, 2); + //xt1 was ready, it was pruned (bc of 155 tag conflict) but was revalidated and resubmitted + // (API does not know about 155). + assert_eq!(pool.validated_pool().status().future, 1); + + let pending: Vec<_> = pool.validated_pool().futures().iter().map(|(hash, _)| *hash).collect(); + assert_eq!(pending[0], api.hash_and_length(&xt1).0); } fn block_event(header: Header) -> ChainEvent { @@ -297,7 +314,7 @@ fn should_revalidate_during_maintenance() { .expect("1. Imported"); let watcher = block_on(pool.submit_and_watch(api.expect_hash_from_number(0), SOURCE, xt2.clone())) - .expect("2. Imported"); + .expect("import"); //todo assert_eq!(pool.status().ready, 2); assert_eq!(api.validation_requests().len(), 2); @@ -929,14 +946,16 @@ fn ready_set_should_not_resolve_before_block_update() { let xt1 = uxt(Alice, 209); block_on(pool.submit_one(api.expect_hash_from_number(0), SOURCE, xt1.clone())) .expect("1. Imported"); + let hash_of_1 = api.push_block_with_parent(api.genesis_hash(), vec![], true).hash(); - assert!(pool.ready_at(1).now_or_never().is_none()); + assert!(pool.ready_at(hash_of_1).now_or_never().is_none()); } #[test] fn ready_set_should_resolve_after_block_update() { let (pool, api, _guard) = maintained_pool(); let header = api.push_block(1, vec![], true); + let hash_of_1 = header.hash(); let xt1 = uxt(Alice, 209); @@ -944,13 +963,14 @@ fn ready_set_should_resolve_after_block_update() { .expect("1. Imported"); block_on(pool.maintain(block_event(header))); - assert!(pool.ready_at(1).now_or_never().is_some()); + assert!(pool.ready_at(hash_of_1).now_or_never().is_some()); } #[test] fn ready_set_should_eventually_resolve_when_block_update_arrives() { let (pool, api, _guard) = maintained_pool(); let header = api.push_block(1, vec![], true); + let hash_of_1 = header.hash(); let xt1 = uxt(Alice, 209); @@ -960,7 +980,7 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() { let noop_waker = futures::task::noop_waker(); let mut context = futures::task::Context::from_waker(&noop_waker); - let mut ready_set_future = pool.ready_at(1); + let mut ready_set_future = pool.ready_at(hash_of_1); if ready_set_future.poll_unpin(&mut context).is_ready() { panic!("Ready set should not be ready before block update!"); } @@ -1052,9 +1072,9 @@ fn stale_transactions_are_pruned() { // Our initial transactions let xts = vec![ - Transfer { from: Alice.into(), to: Bob.into(), nonce: 1, amount: 1 }, - Transfer { from: Alice.into(), to: Bob.into(), nonce: 2, amount: 1 }, - Transfer { from: Alice.into(), to: Bob.into(), nonce: 3, amount: 1 }, + Transfer { from: Alice.into(), to: Bob.into(), nonce: 10, amount: 1 }, + Transfer { from: Alice.into(), to: Bob.into(), nonce: 11, amount: 1 }, + Transfer { from: Alice.into(), to: Bob.into(), nonce: 12, amount: 1 }, ]; let (pool, api, _guard) = maintained_pool(); @@ -1086,6 +1106,7 @@ fn stale_transactions_are_pruned() { block_on(pool.maintain(block_event(header))); // The imported transactions have a different hash and should not evict our initial // transactions. + log::debug!("-> {:?}", pool.status()); assert_eq!(pool.status().future, 3); // Import enough blocks to make our transactions stale diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 41ece6c9a27f..2d0daf82997d 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -44,8 +44,10 @@ 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 } frame-executive = { optional = true, workspace = true } frame-system-rpc-runtime-api = { optional = true, workspace = true } @@ -67,19 +69,20 @@ pallet-examples = { workspace = true } default = ["runtime", "std"] experimental = ["frame-support/experimental"] runtime = [ + "frame-executive", + "frame-system-rpc-runtime-api", "sp-api", "sp-block-builder", "sp-consensus-aura", "sp-consensus-grandpa", + "sp-genesis-builder", "sp-inherents", + "sp-keyring", "sp-offchain", "sp-session", "sp-storage", "sp-transaction-pool", "sp-version", - - "frame-executive", - "frame-system-rpc-runtime-api", ] std = [ "codec/std", @@ -98,8 +101,10 @@ std = [ "sp-consensus-aura?/std", "sp-consensus-grandpa?/std", "sp-core/std", + "sp-genesis-builder?/std", "sp-inherents?/std", "sp-io/std", + "sp-keyring?/std", "sp-offchain?/std", "sp-runtime/std", "sp-session?/std", diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index 5442e8779020..625cabf3457f 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -85,11 +85,13 @@ impl pallet_collective::Config for Test { parameter_types! { pub const BasicDeposit: u64 = 100; pub const ByteDeposit: u64 = 10; + pub const UsernameDeposit: u64 = 10; pub const SubAccountDeposit: u64 = 100; pub const MaxSubAccounts: u32 = 2; pub const MaxAdditionalFields: u32 = 2; pub const MaxRegistrars: u32 = 20; pub const PendingUsernameExpiration: u64 = 100; + pub const UsernameGracePeriod: u64 = 10; } ord_parameter_types! { pub const One: u64 = 1; @@ -106,6 +108,7 @@ impl pallet_identity::Config for Test { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -117,6 +120,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = AccountU64; type UsernameAuthorityOrigin = EnsureOneOrRoot; type PendingUsernameExpiration = PendingUsernameExpiration; + type UsernameGracePeriod = UsernameGracePeriod; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); @@ -149,7 +153,7 @@ impl IdentityVerifier for AllianceIdentityVerifier { fn has_good_judgement(who: &AccountId) -> bool { if let Some(judgements) = - IdentityOf::::get(who).map(|(registration, _)| registration.judgements) + IdentityOf::::get(who).map(|registration| registration.judgements) { judgements .iter() diff --git a/substrate/frame/alliance/src/tests.rs b/substrate/frame/alliance/src/tests.rs index ec31ebf6a47a..2397ebfe7db4 100644 --- a/substrate/frame/alliance/src/tests.rs +++ b/substrate/frame/alliance/src/tests.rs @@ -244,7 +244,7 @@ fn vote_works() { fn close_works() { new_test_ext().execute_with(|| { let (proposal, proposal_len, hash) = make_remark_proposal(42); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; assert_ok!(Alliance::propose( RuntimeOrigin::signed(1), 3, @@ -645,8 +645,8 @@ fn remove_unscrupulous_items_works() { #[test] fn weights_sane() { let info = crate::Call::::join_alliance {}.get_dispatch_info(); - assert_eq!(<() as crate::WeightInfo>::join_alliance(), info.weight); + assert_eq!(<() as crate::WeightInfo>::join_alliance(), info.call_weight); let info = crate::Call::::nominate_ally { who: 10 }.get_dispatch_info(); - assert_eq!(<() as crate::WeightInfo>::nominate_ally(), info.weight); + assert_eq!(<() as crate::WeightInfo>::nominate_ally(), info.call_weight); } 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/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 9aea19dbf57c..dd7feb08f9f4 100644 --- a/substrate/frame/asset-conversion/src/weights.rs +++ b/substrate/frame/asset-conversion/src/weights.rs @@ -18,25 +18,27 @@ //! 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 #![cfg_attr(rustfmt, rustfmt_skip)] @@ -70,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) @@ -95,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)) } @@ -116,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)) } @@ -130,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())) @@ -147,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())) @@ -170,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()))) } @@ -193,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) @@ -218,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)) } @@ -239,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)) } @@ -253,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())) @@ -270,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())) @@ -293,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/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/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/tests.rs b/substrate/frame/assets/src/tests.rs index af605c5a3c64..75a6139702c6 100644 --- a/substrate/frame/assets/src/tests.rs +++ b/substrate/frame/assets/src/tests.rs @@ -1785,10 +1785,10 @@ fn multiple_transfer_alls_work_ok() { #[test] fn weights_sane() { let info = crate::Call::::create { id: 10, admin: 4, min_balance: 3 }.get_dispatch_info(); - assert_eq!(<() as crate::WeightInfo>::create(), info.weight); + assert_eq!(<() as crate::WeightInfo>::create(), info.call_weight); let info = crate::Call::::finish_destroy { id: 10 }.get_dispatch_info(); - assert_eq!(<() as crate::WeightInfo>::finish_destroy(), info.weight); + assert_eq!(<() as crate::WeightInfo>::finish_destroy(), info.call_weight); } #[test] 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/aura/src/lib.rs b/substrate/frame/aura/src/lib.rs index f829578fb285..c74e864ea0d9 100644 --- a/substrate/frame/aura/src/lib.rs +++ b/substrate/frame/aura/src/lib.rs @@ -400,7 +400,9 @@ impl OnTimestampSet for Pallet { assert_eq!( CurrentSlot::::get(), timestamp_slot, - "Timestamp slot must match `CurrentSlot`" + "Timestamp slot must match `CurrentSlot`. This likely means that the configured block \ + time in the node and/or rest of the runtime is not compatible with Aura's \ + `SlotDuration`", ); } } 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/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/equivocation.rs b/substrate/frame/babe/src/equivocation.rs index 4be07bdae1f0..524ad23e58ee 100644 --- a/substrate/frame/babe/src/equivocation.rs +++ b/substrate/frame/babe/src/equivocation.rs @@ -100,7 +100,7 @@ impl Offence for EquivocationOffence { /// /// This type implements `OffenceReportSystem` such that: /// - Equivocation reports are published on-chain as unsigned extrinsic via -/// `offchain::SendTransactionTypes`. +/// `offchain::CreateTransactionBase`. /// - On-chain validity checks and processing are mostly delegated to the user provided generic /// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. /// - Offence reporter for unsigned transactions is fetched via the the authorship pallet. @@ -110,7 +110,7 @@ impl OffenceReportSystem, (EquivocationProof>, T::KeyOwnerProof)> for EquivocationReportSystem where - T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, + T: Config + pallet_authorship::Config + frame_system::offchain::CreateInherent>, R: ReportOffence< T::AccountId, P::IdentificationTuple, @@ -132,7 +132,8 @@ where equivocation_proof: Box::new(equivocation_proof), key_owner_proof, }; - let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); + let xt = T::create_inherent(call.into()); + let res = SubmitTransaction::>::submit_transaction(xt); match res { Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report"), Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 4e4052b2b566..23857470adc4 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -68,14 +68,23 @@ impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; } -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = TestXt; } +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + TestXt::new_bare(call) + } +} + impl_opaque_keys! { pub struct MockSessionKeys { pub babe_authority: super::Pallet, @@ -230,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( @@ -291,7 +300,7 @@ pub fn new_test_ext_with_pairs( authorities_len: usize, ) -> (Vec, sp_io::TestExternalities) { let pairs = (0..authorities_len) - .map(|i| AuthorityPair::from_seed(&U256::from(i).into())) + .map(|i| AuthorityPair::from_seed(&U256::from(i).to_little_endian())) .collect::>(); let public = pairs.iter().map(|p| p.public()).collect(); diff --git a/substrate/frame/babe/src/tests.rs b/substrate/frame/babe/src/tests.rs index b9a214ca105c..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); @@ -906,7 +906,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // it should have non-zero weight and the fee has to be paid. // TODO: account for proof size weight - assert!(info.weight.ref_time() > 0); + assert!(info.call_weight.ref_time() > 0); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. 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 44899e5b7d8d..f0117555c37e 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -52,6 +52,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ diff --git a/substrate/frame/balances/src/impl_fungible.rs b/substrate/frame/balances/src/impl_fungible.rs index cf95a97d191f..4470c3cc9eb1 100644 --- a/substrate/frame/balances/src/impl_fungible.rs +++ b/substrate/frame/balances/src/impl_fungible.rs @@ -354,7 +354,9 @@ impl, I: 'static> fungible::Balanced for Pallet Self::deposit_event(Event::::Withdraw { who: who.clone(), amount }); } fn done_issue(amount: Self::Balance) { - Self::deposit_event(Event::::Issued { amount }); + if !amount.is_zero() { + Self::deposit_event(Event::::Issued { amount }); + } } fn done_rescind(amount: Self::Balance) { Self::deposit_event(Event::::Rescinded { amount }); 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 a4984b34f6db..5ad818e5bfa2 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -30,6 +30,7 @@ use frame_support::{ StorageNoopGuard, }; use frame_system::Event as SysEvent; +use sp_runtime::traits::DispatchTransaction; const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; @@ -258,20 +259,22 @@ fn lock_should_work_reserve() { TokenError::Frozen ); assert_noop!(Balances::reserve(&1, 1), Error::::LiquidityRestrictions,); - assert!( as SignedExtension>::pre_dispatch( + assert!(ChargeTransactionPayment::::validate_and_prepare( ChargeTransactionPayment::from(1), - &1, + Some(1).into(), CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); - assert!( as SignedExtension>::pre_dispatch( + assert!(ChargeTransactionPayment::::validate_and_prepare( ChargeTransactionPayment::from(0), - &1, + Some(1).into(), CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); }); @@ -289,20 +292,22 @@ fn lock_should_work_tx_fee() { TokenError::Frozen ); assert_noop!(Balances::reserve(&1, 1), Error::::LiquidityRestrictions,); - assert!( as SignedExtension>::pre_dispatch( + assert!(ChargeTransactionPayment::::validate_and_prepare( ChargeTransactionPayment::from(1), - &1, + Some(1).into(), CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); - assert!( as SignedExtension>::pre_dispatch( + assert!(ChargeTransactionPayment::::validate_and_prepare( ChargeTransactionPayment::from(0), - &1, + Some(1).into(), CALL, &info_from_weight(Weight::from_parts(1, 0)), 1, + 0, ) .is_err()); }); diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index ba0cdabdabbb..bf49ad9f0a1f 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -37,7 +37,7 @@ use scale_info::TypeInfo; use sp_core::hexdisplay::HexDisplay; use sp_io; use sp_runtime::{ - traits::{BadOrigin, SignedExtension, Zero}, + traits::{BadOrigin, Zero}, ArithmeticError, BuildStorage, DispatchError, DispatchResult, FixedPointNumber, RuntimeDebug, TokenError, }; @@ -104,7 +104,6 @@ impl pallet_transaction_payment::Config for Test { type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); } parameter_types! { @@ -275,7 +274,7 @@ pub fn events() -> Vec { /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { - DispatchInfo { weight: w, ..Default::default() } + DispatchInfo { call_weight: w, ..Default::default() } } /// Check that the total-issuance matches the sum of all accounts' total balances. @@ -298,10 +297,10 @@ pub fn ensure_ti_valid() { #[test] fn weights_sane() { let info = crate::Call::::transfer_allow_death { dest: 10, value: 4 }.get_dispatch_info(); - assert_eq!(<() as crate::WeightInfo>::transfer_allow_death(), info.weight); + assert_eq!(<() as crate::WeightInfo>::transfer_allow_death(), info.call_weight); let info = crate::Call::::force_unreserve { who: 10, amount: 4 }.get_dispatch_info(); - assert_eq!(<() as crate::WeightInfo>::force_unreserve(), info.weight); + assert_eq!(<() as crate::WeightInfo>::force_unreserve(), info.call_weight); } #[test] 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/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/src/equivocation.rs b/substrate/frame/beefy/src/equivocation.rs index 15345e6ae199..3a49b9e169ce 100644 --- a/substrate/frame/beefy/src/equivocation.rs +++ b/substrate/frame/beefy/src/equivocation.rs @@ -118,7 +118,7 @@ where /// /// This type implements `OffenceReportSystem` such that: /// - Equivocation reports are published on-chain as unsigned extrinsic via -/// `offchain::SendTransactionTypes`. +/// `offchain::CreateTransactionBase`. /// - On-chain validity checks and processing are mostly delegated to the user provided generic /// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. /// - Offence reporter for unsigned transactions is fetched via the authorship pallet. @@ -262,7 +262,7 @@ impl EquivocationEvidenceFor { impl OffenceReportSystem, EquivocationEvidenceFor> for EquivocationReportSystem where - T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, + T: Config + pallet_authorship::Config + frame_system::offchain::CreateInherent>, R: ReportOffence< T::AccountId, P::IdentificationTuple, @@ -278,7 +278,8 @@ where use frame_system::offchain::SubmitTransaction; let call: Call = evidence.into(); - let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); + let xt = T::create_inherent(call.into()); + let res = SubmitTransaction::>::submit_transaction(xt); match res { Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report."), Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 5c79d8f7d7d7..7ae41c609180 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -75,14 +75,23 @@ impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; } -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = TestXt; } +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + TestXt::new_bare(call) + } +} + #[derive(Clone, Debug, Decode, Encode, PartialEq, TypeInfo)] pub struct MockAncestryProofContext { pub is_valid: bool, @@ -357,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..0c74d94b33b8 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -38,6 +38,9 @@ static_assertions = { workspace = true, default-features = true } array-bytes = { workspace = true, default-features = true } rusty-fork = { workspace = true } sp-keystore = { workspace = true, default-features = true } +sc-client-db = { workspace = true } +sp-state-machine = { workspace = true } +sp-externalities = { 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/src/lib.rs b/substrate/frame/benchmarking/src/lib.rs index 625da2a24bd0..6e21356e9d47 100644 --- a/substrate/frame/benchmarking/src/lib.rs +++ b/substrate/frame/benchmarking/src/lib.rs @@ -311,6 +311,83 @@ pub use v1::*; /// } /// } /// ``` +/// +/// ## Migrate from v1 to v2 +/// +/// To migrate your code from benchmarking v1 to benchmarking v2, you may follow these +/// steps: +/// 1. Change the import from `frame_benchmarking::v1::` to `frame_benchmarking::v2::*`, or +/// `frame::benchmarking::prelude::*` under the umbrella crate; +/// 2. Move the code inside the v1 `benchmarks! { ... }` block to the v2 benchmarks module `mod +/// benchmarks { ... }` under the benchmarks macro (`#[benchmarks]` for a regular module, or +/// `#[instance_benchmarks]` to set up the module in instance benchmarking mode); +/// 3. Turn each v1 benchmark into a function inside the v2 benchmarks module with the same name, +/// having either a blank return type or a return type compatible with `Result<(), +/// BenchmarkError>`. For instance, `foo { ... }` can become `fn foo() -> Result<(), +/// BenchmarkError>`. More in detail: +/// 1. Move all the v1 complexity parameters as [ParamRange](`v2::ParamRange`) arguments to the +/// v2 function, and their setup code to the body of the function. For instance, `let y in 0 +/// .. 10 => setup(y)?;` from v1 will give a `y: Linear<0, 10>` argument to the corresponding +/// function in v2, while `setup(y)?;` will be moved to the body of the function; +/// 2. Move all the v1 setup code to the body of the v2 function; +/// 3. Move the benchmarked code to the body of the v2 function under the appropriate macro +/// attribute: `#[extrinsic_call]` for extrinsic pallet calls and `#[block]` for blocks of +/// code; +/// 4. Move the v1 verify code block to the body of the v2 function, after the +/// `#[extrinsic_call]` or `#[block]` attribute. +/// 5. If the function returns a `Result<(), BenchmarkError>`, end with `Ok(())`. +/// +/// As for tests, the code is the same as v1 (see [Benchmark Tests](#benchmark-tests)). +/// +/// As an example migration, the following v1 code +/// +/// ```ignore +/// #![cfg(feature = "runtime-benchmarks")] +/// +/// use frame_benchmarking::v1::*; +/// +/// benchmarks! { +/// +/// // first dispatchable: this is a user dispatchable and operates on a `u8` vector of +/// // size `l` +/// foo { +/// let caller = funded_account::(b"caller", 0); +/// let l in 1 .. 10_000 => initialize_l(l); +/// }: { +/// _(RuntimeOrigin::Signed(caller), vec![0u8; l]) +/// } verify { +/// assert_last_event::(Event::FooExecuted { result: Ok(()) }.into()); +/// } +/// } +/// ``` +/// +/// would become the following v2 code: +/// +/// ```ignore +/// #![cfg(feature = "runtime-benchmarks")] +/// +/// use frame_benchmarking::v2::*; +/// +/// #[benchmarks] +/// mod benchmarks { +/// use super::*; +/// +/// // first dispatchable: foo; this is a user dispatchable and operates on a `u8` vector of +/// // size `l` +/// #[benchmark] +/// fn foo(l: Linear<1 .. 10_000>) -> Result<(), BenchmarkError> { +/// let caller = funded_account::(b"caller", 0); +/// initialize_l(l); +/// +/// #[extrinsic_call] +/// _(RuntimeOrigin::Signed(caller), vec![0u8; l]); +/// +/// // Everything onwards will be treated as test. +/// assert_last_event::(Event::FooExecuted { result: Ok(()) }.into()); +/// Ok(()) +/// } +/// } +/// ``` pub mod v2 { pub use super::*; pub use frame_support_procedural::{ 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/src/benchmarking.rs b/substrate/frame/bounties/src/benchmarking.rs index de93ba5c4ce7..8ad85d5420ed 100644 --- a/substrate/frame/bounties/src/benchmarking.rs +++ b/substrate/frame/bounties/src/benchmarking.rs @@ -26,13 +26,17 @@ use frame_benchmarking::v1::{ account, benchmarks_instance_pallet, whitelisted_caller, BenchmarkError, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use sp_runtime::traits::Bounded; +use sp_runtime::traits::{BlockNumberProvider, Bounded}; use crate::Pallet as Bounties; use pallet_treasury::Pallet as Treasury; const SEED: u32 = 0; +fn set_block_number, I: 'static>(n: BlockNumberFor) { + >::BlockNumberProvider::set_block_number(n); +} + // 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 { @@ -78,7 +82,8 @@ fn create_bounty, I: 'static>( let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + set_block_number::(T::SpendPeriod::get()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup.clone(), fee)?; Bounties::::accept_curator(RawOrigin::Signed(curator).into(), bounty_id)?; Ok((curator_lookup, bounty_id)) @@ -116,16 +121,32 @@ benchmarks_instance_pallet! { let bounty_id = BountyCount::::get() - 1; let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; + set_block_number::(T::SpendPeriod::get()); + 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(BlockNumberFor::::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::(); let (curator_lookup, bounty_id) = create_bounty::()?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); let bounty_id = BountyCount::::get() - 1; - frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 2u32.into()); + set_block_number::(T::SpendPeriod::get() + T::BountyUpdatePeriod::get() + 2u32.into()); let caller = whitelisted_caller(); }: _(RawOrigin::Signed(caller), bounty_id) @@ -137,14 +158,15 @@ benchmarks_instance_pallet! { let bounty_id = BountyCount::::get() - 1; let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin.clone(), bounty_id)?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + set_block_number::(T::SpendPeriod::get()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); Bounties::::propose_curator(approve_origin, bounty_id, curator_lookup, fee)?; }: _(RawOrigin::Signed(curator), bounty_id) award_bounty { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; @@ -155,7 +177,7 @@ benchmarks_instance_pallet! { claim_bounty { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; @@ -164,7 +186,7 @@ benchmarks_instance_pallet! { let beneficiary = T::Lookup::unlookup(beneficiary_account.clone()); Bounties::::award_bounty(RawOrigin::Signed(curator.clone()).into(), bounty_id, beneficiary)?; - frame_system::Pallet::::set_block_number(T::BountyDepositPayoutDelay::get() + 1u32.into()); + set_block_number::(T::SpendPeriod::get() + T::BountyDepositPayoutDelay::get() + 1u32.into()); ensure!(T::Currency::free_balance(&beneficiary_account).is_zero(), "Beneficiary already has balance"); }: _(RawOrigin::Signed(curator), bounty_id) @@ -184,7 +206,7 @@ benchmarks_instance_pallet! { close_bounty_active { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); let bounty_id = BountyCount::::get() - 1; let approve_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -196,7 +218,7 @@ benchmarks_instance_pallet! { extend_bounty_expiry { setup_pot_account::(); let (curator_lookup, bounty_id) = create_bounty::()?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); let bounty_id = BountyCount::::get() - 1; let curator = T::Lookup::lookup(curator_lookup).map_err(<&str>::from)?; diff --git a/substrate/frame/bounties/src/lib.rs b/substrate/frame/bounties/src/lib.rs index e30d6fa2d143..3ed408a19120 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. @@ -96,7 +98,7 @@ use frame_support::traits::{ }; use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, Saturating, StaticLookup, Zero}, + traits::{AccountIdConversion, BadOrigin, BlockNumberProvider, Saturating, StaticLookup, Zero}, DispatchResult, Permill, RuntimeDebug, }; @@ -174,6 +176,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 +188,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] @@ -326,6 +336,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 +482,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. @@ -488,7 +508,7 @@ pub mod pallet { // If the sender is not the curator, and the curator is inactive, // slash the curator. if sender != *curator { - let block_number = frame_system::Pallet::::block_number(); + let block_number = Self::treasury_block_number(); if *update_due < block_number { slash_curator(curator, &mut bounty.curator_deposit); // Continue to change bounty status below... @@ -552,8 +572,8 @@ pub mod pallet { T::Currency::reserve(curator, deposit)?; bounty.curator_deposit = deposit; - let update_due = frame_system::Pallet::::block_number() + - T::BountyUpdatePeriod::get(); + let update_due = + Self::treasury_block_number() + T::BountyUpdatePeriod::get(); bounty.status = BountyStatus::Active { curator: curator.clone(), update_due }; @@ -607,8 +627,7 @@ pub mod pallet { bounty.status = BountyStatus::PendingPayout { curator: signer, beneficiary: beneficiary.clone(), - unlock_at: frame_system::Pallet::::block_number() + - T::BountyDepositPayoutDelay::get(), + unlock_at: Self::treasury_block_number() + T::BountyDepositPayoutDelay::get(), }; Ok(()) @@ -639,10 +658,7 @@ pub mod pallet { if let BountyStatus::PendingPayout { curator, beneficiary, unlock_at } = bounty.status { - ensure!( - frame_system::Pallet::::block_number() >= unlock_at, - Error::::Premature - ); + ensure!(Self::treasury_block_number() >= unlock_at, Error::::Premature); let bounty_account = Self::bounty_account_id(bounty_id); let balance = T::Currency::free_balance(&bounty_account); let fee = bounty.fee.min(balance); // just to be safe @@ -666,6 +682,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, @@ -727,7 +744,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()) @@ -763,7 +780,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()) @@ -795,7 +814,7 @@ pub mod pallet { match bounty.status { BountyStatus::Active { ref curator, ref mut update_due } => { ensure!(*curator == signer, Error::::RequireCurator); - *update_due = (frame_system::Pallet::::block_number() + + *update_due = (Self::treasury_block_number() + T::BountyUpdatePeriod::get()) .max(*update_due); }, @@ -808,6 +827,52 @@ 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] @@ -860,6 +925,14 @@ impl, I: 'static> Pallet { } 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 { + >::BlockNumberProvider::current_block_number() + } + + /// Calculate the deposit required for a curator. pub fn calculate_curator_deposit(fee: &BalanceOf) -> BalanceOf { let mut deposit = T::CuratorDepositMultiplier::get() * *fee; @@ -942,7 +1015,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 c152391d807a..447d0edb4122 100644 --- a/substrate/frame/bounties/src/tests.rs +++ b/substrate/frame/bounties/src/tests.rs @@ -40,6 +40,12 @@ use super::Event as BountiesEvent; type Block = frame_system::mocking::MockBlock; +// This function directly jumps to a block number, and calls `on_initialize`. +fn go_to_block(n: u64) { + ::BlockNumberProvider::set_block_number(n); + >::on_initialize(n); +} + frame_support::construct_runtime!( pub enum Test { @@ -98,6 +104,7 @@ impl pallet_treasury::Config for Test { type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = ConstU64<10>; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -120,6 +127,7 @@ impl pallet_treasury::Config for Test { type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = ConstU64<10>; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -186,7 +194,9 @@ impl ExtBuilder { .build_storage() .unwrap() .into(); - ext.execute_with(|| System::set_block_number(1)); + ext.execute_with(|| { + ::BlockNumberProvider::set_block_number(1) + }); ext } @@ -199,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); @@ -226,13 +249,14 @@ 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); assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 100, 3) }); - >::on_initialize(1); + go_to_block(1); assert_eq!(Balances::free_balance(3), 0); assert_eq!(Treasury::pot(), 100); }); @@ -245,13 +269,14 @@ fn unused_pot_should_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(pallet_balances::TotalIssuance::::get(), init_total_issuance + 100); - >::on_initialize(2); + go_to_block(2); assert_eq!(Treasury::pot(), 50); assert_eq!(pallet_balances::TotalIssuance::::get(), init_total_issuance + 50); }); } #[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); @@ -259,13 +284,14 @@ fn accepted_spend_proposal_enacted_on_spend_period() { assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 100, 3) }); - >::on_initialize(2); + go_to_block(2); assert_eq!(Balances::free_balance(3), 100); assert_eq!(Treasury::pot(), 0); }); } #[test] +#[allow(deprecated)] fn pot_underflow_should_not_diminish() { ExtBuilder::default().build_and_execute(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); @@ -273,11 +299,11 @@ fn pot_underflow_should_not_diminish() { assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 150, 3) }); - >::on_initialize(2); + go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed assert_ok!(Balances::deposit_into_existing(&Treasury::account_id(), 100)); - >::on_initialize(4); + go_to_block(4); assert_eq!(Balances::free_balance(3), 150); // Fund has been spent assert_eq!(Treasury::pot(), 25); // Pot has finally changed }); @@ -286,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); @@ -294,12 +321,12 @@ fn treasury_account_doesnt_get_deleted() { assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), treasury_balance, 3) }); - >::on_initialize(2); + go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), Treasury::pot(), 3) }); - >::on_initialize(4); + go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied assert_eq!(Balances::free_balance(Treasury::account_id()), 1); // but the account is still there }); @@ -308,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)] } @@ -322,7 +350,8 @@ fn inexistent_account_works() { assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 99, 3) }); assert_ok!({ Treasury::spend_local(RuntimeOrigin::root(), 1, 3) }); - >::on_initialize(2); + go_to_block(2); + assert_eq!(Treasury::pot(), 0); // Pot hasn't changed assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed @@ -330,7 +359,7 @@ fn inexistent_account_works() { assert_eq!(Treasury::pot(), 99); // Pot now contains funds assert_eq!(Balances::free_balance(Treasury::account_id()), 100); // Account does exist - >::on_initialize(4); + go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot has changed assert_eq!(Balances::free_balance(3), 99); // Balance of `3` has changed @@ -340,8 +369,6 @@ fn inexistent_account_works() { #[test] fn propose_bounty_works() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); - Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); @@ -377,8 +404,6 @@ fn propose_bounty_works() { #[test] fn propose_bounty_validation_works() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); - Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); @@ -404,9 +429,9 @@ fn propose_bounty_validation_works() { } #[test] +#[allow(deprecated)] fn close_bounty_works() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_noop!(Bounties::close_bounty(RuntimeOrigin::root(), 0), Error::::InvalidIndex); @@ -431,7 +456,6 @@ fn close_bounty_works() { #[test] fn approve_bounty_works() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_noop!( Bounties::approve_bounty(RuntimeOrigin::root(), 0), @@ -466,7 +490,7 @@ fn approve_bounty_works() { assert_eq!(Balances::reserved_balance(0), deposit); assert_eq!(Balances::free_balance(0), 100 - deposit); - >::on_initialize(2); + go_to_block(2); // return deposit assert_eq!(Balances::reserved_balance(0), 0); @@ -492,7 +516,6 @@ fn approve_bounty_works() { #[test] fn assign_curator_works() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_noop!( @@ -504,8 +527,7 @@ fn assign_curator_works() { assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_noop!( Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 50), @@ -562,14 +584,12 @@ fn assign_curator_works() { #[test] fn unassign_curator_works() { ExtBuilder::default().build_and_execute(|| { - 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(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); let fee = 4; @@ -615,15 +635,13 @@ fn unassign_curator_works() { #[test] fn award_and_claim_bounty_works() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 10); assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); let fee = 4; assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); @@ -653,8 +671,7 @@ fn award_and_claim_bounty_works() { assert_noop!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0), Error::::Premature); - System::set_block_number(5); - >::on_initialize(5); + go_to_block(5); assert_ok!(Balances::transfer_allow_death( RuntimeOrigin::signed(0), @@ -682,23 +699,20 @@ fn award_and_claim_bounty_works() { #[test] fn claim_handles_high_fee() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 30); assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 49)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 3)); - System::set_block_number(5); - >::on_initialize(5); + go_to_block(5); // make fee > balance let res = Balances::slash(&Bounties::bounty_account_id(0), 10); @@ -723,16 +737,13 @@ fn claim_handles_high_fee() { #[test] fn cancel_and_refund() { ExtBuilder::default().build_and_execute(|| { - 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(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Balances::transfer_allow_death( RuntimeOrigin::signed(0), @@ -766,14 +777,12 @@ fn cancel_and_refund() { #[test] fn award_and_cancel() { ExtBuilder::default().build_and_execute(|| { - 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(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 0, 10)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(0), 0)); @@ -809,14 +818,12 @@ fn award_and_cancel() { #[test] fn expire_and_unassign() { ExtBuilder::default().build_and_execute(|| { - 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(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 1, 10)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(1), 0)); @@ -824,16 +831,14 @@ fn expire_and_unassign() { assert_eq!(Balances::free_balance(1), 93); assert_eq!(Balances::reserved_balance(1), 5); - System::set_block_number(22); - >::on_initialize(22); + go_to_block(22); assert_noop!( Bounties::unassign_curator(RuntimeOrigin::signed(0), 0), Error::::Premature ); - System::set_block_number(23); - >::on_initialize(23); + go_to_block(23); assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(0), 0)); @@ -857,7 +862,6 @@ fn expire_and_unassign() { #[test] fn extend_expiry() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 10); assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); @@ -869,8 +873,7 @@ fn extend_expiry() { Error::::UnexpectedStatus ); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 10)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); @@ -878,8 +881,7 @@ fn extend_expiry() { assert_eq!(Balances::free_balance(4), 5); assert_eq!(Balances::reserved_balance(4), 5); - System::set_block_number(10); - >::on_initialize(10); + go_to_block(10); assert_noop!( Bounties::extend_bounty_expiry(RuntimeOrigin::signed(0), 0, Vec::new()), @@ -913,8 +915,7 @@ fn extend_expiry() { } ); - System::set_block_number(25); - >::on_initialize(25); + go_to_block(25); assert_noop!( Bounties::unassign_curator(RuntimeOrigin::signed(0), 0), @@ -993,13 +994,11 @@ fn genesis_funding_works() { #[test] fn unassign_curator_self() { ExtBuilder::default().build_and_execute(|| { - 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(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 1, 10)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(1), 0)); @@ -1007,8 +1006,7 @@ fn unassign_curator_self() { assert_eq!(Balances::free_balance(1), 93); assert_eq!(Balances::reserved_balance(1), 5); - System::set_block_number(8); - >::on_initialize(8); + go_to_block(8); assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(1), 0)); @@ -1040,7 +1038,6 @@ fn accept_curator_handles_different_deposit_calculations() { let value = 88; let fee = 42; - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&user, 100); // Allow for a larger spend limit: @@ -1048,8 +1045,7 @@ fn accept_curator_handles_different_deposit_calculations() { assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); @@ -1070,8 +1066,7 @@ fn accept_curator_handles_different_deposit_calculations() { assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); - System::set_block_number(4); - >::on_initialize(4); + go_to_block(4); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); @@ -1096,8 +1091,7 @@ fn accept_curator_handles_different_deposit_calculations() { assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); - System::set_block_number(6); - >::on_initialize(6); + go_to_block(6); assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); @@ -1114,7 +1108,6 @@ fn approve_bounty_works_second_instance() { // Set burn to 0 to make tracking funds easier. Burn::set(Permill::from_percent(0)); - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&Treasury1::account_id(), 201); assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); @@ -1122,7 +1115,7 @@ fn approve_bounty_works_second_instance() { assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 10, b"12345".to_vec())); assert_ok!(Bounties1::approve_bounty(RuntimeOrigin::root(), 0)); - >::on_initialize(2); + go_to_block(2); >::on_initialize(2); // Bounties 1 is funded... but from where? @@ -1137,8 +1130,6 @@ fn approve_bounty_works_second_instance() { #[test] fn approve_bounty_insufficient_spend_limit_errors() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); - Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); @@ -1155,8 +1146,6 @@ fn approve_bounty_insufficient_spend_limit_errors() { #[test] fn approve_bounty_instance1_insufficient_spend_limit_errors() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); - Balances::make_free_balance_be(&Treasury1::account_id(), 101); assert_eq!(Treasury1::pot(), 100); @@ -1173,7 +1162,6 @@ fn approve_bounty_instance1_insufficient_spend_limit_errors() { #[test] fn propose_curator_insufficient_spend_limit_errors() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); // Temporarily set a larger spend limit; @@ -1181,8 +1169,7 @@ fn propose_curator_insufficient_spend_limit_errors() { assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 51, b"12345".to_vec())); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); SpendLimit::set(50); // 51 will not work since the limit is 50. @@ -1196,7 +1183,6 @@ fn propose_curator_insufficient_spend_limit_errors() { #[test] fn propose_curator_instance1_insufficient_spend_limit_errors() { ExtBuilder::default().build_and_execute(|| { - System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); // Temporarily set a larger spend limit; @@ -1204,7 +1190,6 @@ fn propose_curator_instance1_insufficient_spend_limit_errors() { assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 11, b"12345".to_vec())); assert_ok!(Bounties1::approve_bounty(RuntimeOrigin::root(), 0)); - System::set_block_number(2); >::on_initialize(2); SpendLimit1::set(10); @@ -1215,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/src/benchmarking.rs b/substrate/frame/broker/src/benchmarking.rs index 595bf564f7e1..9ef9b1254435 100644 --- a/substrate/frame/broker/src/benchmarking.rs +++ b/substrate/frame/broker/src/benchmarking.rs @@ -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(), @@ -787,7 +789,7 @@ mod benches { let core_count = n.try_into().unwrap(); let config = new_config_record::(); - let now = frame_system::Pallet::::block_number(); + let now = RCBlockNumberProviderOf::::current_block_number(); let end_price = 10_000_000u32.into(); let commit_timeslice = Broker::::latest_timeslice_ready_to_commit(&config); let sale = SaleInfoRecordOf:: { @@ -844,9 +846,11 @@ mod benches { } 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(), diff --git a/substrate/frame/broker/src/dispatchable_impls.rs b/substrate/frame/broker/src/dispatchable_impls.rs index 5fbd957d7908..733d96625da0 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 { @@ -91,7 +91,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 +119,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 +171,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 +569,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..ed16b98d26cc 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. 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/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/child-bounties/src/benchmarking.rs b/substrate/frame/child-bounties/src/benchmarking.rs index b1f6370f3340..4b2d62cd920e 100644 --- a/substrate/frame/child-bounties/src/benchmarking.rs +++ b/substrate/frame/child-bounties/src/benchmarking.rs @@ -19,16 +19,15 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; - -use alloc::{vec, vec::Vec}; - -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller, BenchmarkError}; +use alloc::vec; +use frame_benchmarking::{v2::*, BenchmarkError}; +use frame_support::ensure; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; - -use crate::Pallet as ChildBounties; use pallet_bounties::Pallet as Bounties; use pallet_treasury::Pallet as Treasury; +use sp_runtime::traits::BlockNumberProvider; + +use crate::*; const SEED: u32 = 0; @@ -56,6 +55,10 @@ struct BenchmarkChildBounty { reason: Vec, } +fn set_block_number(n: BlockNumberFor) { + ::BlockNumberProvider::set_block_number(n); +} + fn setup_bounty( user: u32, description: u32, @@ -116,7 +119,8 @@ fn activate_bounty( let approve_origin = T::SpendOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; Bounties::::approve_bounty(approve_origin, child_bounty_setup.bounty_id)?; - Treasury::::on_initialize(BlockNumberFor::::zero()); + set_block_number::(T::SpendPeriod::get()); + Treasury::::on_initialize(frame_system::Pallet::::block_number()); Bounties::::propose_curator( RawOrigin::Root.into(), child_bounty_setup.bounty_id, @@ -138,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, @@ -155,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, @@ -174,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(BlockNumberFor::::zero()); - frame_system::Pallet::::set_block_number(T::BountyUpdatePeriod::get() + 1u32.into()); + 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." + ); - frame_system::Pallet::::set_block_number(T::BountyDepositPayoutDelay::get()); - 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." + ); - }: _(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."); + 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(BlockNumberFor::::zero()); - }: 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()) + Treasury::::on_initialize(frame_system::Pallet::::block_number()); + + #[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 660a30ca5d26..ea1d9547d465 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::{ @@ -67,7 +71,10 @@ use frame_support::traits::{ }; use sp_runtime::{ - traits::{AccountIdConversion, BadOrigin, CheckedSub, Saturating, StaticLookup, Zero}, + traits::{ + AccountIdConversion, BadOrigin, BlockNumberProvider, CheckedSub, Saturating, StaticLookup, + Zero, + }, DispatchResult, RuntimeDebug, }; @@ -131,7 +138,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] @@ -181,16 +192,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< @@ -202,10 +219,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] @@ -273,15 +307,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( @@ -523,7 +561,7 @@ pub mod pallet { let (parent_curator, update_due) = Self::ensure_bounty_active(parent_bounty_id)?; if sender == parent_curator || - update_due < frame_system::Pallet::::block_number() + update_due < Self::treasury_block_number() { // Slash the child-bounty curator if // + the call is made by the parent bounty curator. @@ -602,7 +640,7 @@ pub mod pallet { child_bounty.status = ChildBountyStatus::PendingPayout { curator: signer, beneficiary: beneficiary.clone(), - unlock_at: frame_system::Pallet::::block_number() + + unlock_at: Self::treasury_block_number() + T::BountyDepositPayoutDelay::get(), }; Ok(()) @@ -664,12 +702,13 @@ pub mod pallet { // Ensure block number is elapsed for processing the // claim. ensure!( - frame_system::Pallet::::block_number() >= *unlock_at, + Self::treasury_block_number() >= *unlock_at, BountiesError::::Premature, ); // 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); @@ -713,7 +752,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; @@ -769,9 +808,29 @@ 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 { + /// 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 { + ::BlockNumberProvider::current_block_number() + } + // This function will calculate the deposit of a curator. fn calculate_curator_deposit( parent_curator: &T::AccountId, @@ -787,11 +846,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( @@ -808,7 +870,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 }); } @@ -867,7 +929,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, @@ -878,7 +941,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; @@ -892,16 +955,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. @@ -909,4 +978,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 125844fa70e2..939983054f66 100644 --- a/substrate/frame/child-bounties/src/tests.rs +++ b/substrate/frame/child-bounties/src/tests.rs @@ -42,6 +42,12 @@ use super::Event as ChildBountiesEvent; type Block = frame_system::mocking::MockBlock; type BountiesError = pallet_bounties::Error; +// This function directly jumps to a block number, and calls `on_initialize`. +fn go_to_block(n: u64) { + ::BlockNumberProvider::set_block_number(n); + >::on_initialize(n); +} + frame_support::construct_runtime!( pub enum Test { @@ -60,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; @@ -76,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; @@ -98,6 +110,7 @@ impl pallet_treasury::Config for Test { type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = ConstU64<10>; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -134,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(); @@ -154,6 +167,7 @@ fn last_event() -> ChildBountiesEvent { } #[test] +#[allow(deprecated)] fn genesis_config_works() { new_test_ext().execute_with(|| { assert_eq!(Treasury::pot(), 0); @@ -184,56 +198,74 @@ fn add_child_bounty() { // Curator, child-bounty curator & beneficiary. // Make the parent bounty. - System::set_block_number(1); + 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() @@ -242,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. @@ -263,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(), ); }); @@ -278,21 +310,24 @@ fn child_bounty_assign_curator() { // 3, Test for DB state of `ChildBounties`. // Make the parent bounty. - System::set_block_number(1); + 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)); - System::set_block_number(2); - >::on_initialize(2); + 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); @@ -301,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() @@ -320,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(), @@ -333,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; @@ -357,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); @@ -383,28 +424,31 @@ fn child_bounty_assign_curator() { fn award_claim_child_bounty() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() @@ -414,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!( @@ -435,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 }, } @@ -445,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 ); - System::set_block_number(9); + 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); @@ -474,29 +534,32 @@ fn award_claim_child_bounty() { fn close_child_bounty_added() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() @@ -504,15 +567,21 @@ fn close_child_bounty_added() { assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); - System::set_block_number(4); + go_to_block(4); // 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); @@ -522,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); }); } @@ -531,29 +600,32 @@ fn close_child_bounty_added() { fn close_child_bounty_active() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() @@ -562,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); }); } @@ -589,29 +667,32 @@ fn close_child_bounty_active() { fn close_child_bounty_pending() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() @@ -621,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 ); @@ -637,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); }); } @@ -650,29 +742,32 @@ fn close_child_bounty_pending() { fn child_bounty_added_unassign_curator() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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 ); }); @@ -692,29 +787,32 @@ fn child_bounty_added_unassign_curator() { fn child_bounty_curator_proposed_unassign_curator() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() @@ -723,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(), @@ -732,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!( @@ -767,43 +874,51 @@ fn child_bounty_active_unassign_curator() { // bounty. Unassign from random account. Should slash. new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); - System::set_block_number(3); - >::on_initialize(3); + go_to_block(3); // 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!( @@ -813,12 +928,11 @@ 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) }, } ); - System::set_block_number(4); - >::on_initialize(4); + go_to_block(4); // Unassign curator - from reject origin. assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::root(), 0, 0)); @@ -836,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!( @@ -852,15 +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) }, } ); - System::set_block_number(5); - >::on_initialize(5); + 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!( @@ -875,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(), @@ -889,15 +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) }, } ); - System::set_block_number(6); - >::on_initialize(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!( @@ -912,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!( @@ -928,25 +1058,23 @@ 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) }, } ); - System::set_block_number(7); - >::on_initialize(7); + go_to_block(7); // 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 ); - System::set_block_number(20); - >::on_initialize(20); + 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!( @@ -961,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); }); } @@ -972,43 +1100,51 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // This can happen when the curator of parent bounty has been unassigned. new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); - System::set_block_number(3); - >::on_initialize(3); + go_to_block(3); // 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!( @@ -1018,23 +1154,21 @@ 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) }, } ); - System::set_block_number(4); - >::on_initialize(4); + go_to_block(4); // Unassign parent bounty curator. assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); - System::set_block_number(5); - >::on_initialize(5); + go_to_block(5); // 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 ); @@ -1054,23 +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 - System::set_block_number(6); - >::on_initialize(6); + 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)); - System::set_block_number(7); - >::on_initialize(7); + 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!( @@ -1080,26 +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) }, } ); - System::set_block_number(8); - >::on_initialize(8); + 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)); - System::set_block_number(9); - >::on_initialize(9); + 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!( @@ -1114,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 }); } @@ -1123,42 +1259,49 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { fn close_parent_with_child_bounty() { new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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 ); - System::set_block_number(2); - >::on_initialize(2); + 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() )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); - System::set_block_number(4); - >::on_initialize(4); + go_to_block(4); // Try close parent-bounty. // Child bounty active, can't close parent. @@ -1167,17 +1310,19 @@ fn close_parent_with_child_bounty() { BountiesError::HasActiveChildBounty ); - System::set_block_number(2); - // Close child-bounty. assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::root(), 0, 0)); // 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); }); } @@ -1187,46 +1332,59 @@ fn children_curator_fee_calculation_test() { // from parent bounty fee when claiming bounties. new_test_ext().execute_with(|| { // Make the parent bounty. - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Balances::free_balance(Treasury::account_id()), 101); 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)); - System::set_block_number(2); - >::on_initialize(2); + 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() )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); - System::set_block_number(4); - >::on_initialize(4); + go_to_block(4); 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; @@ -1238,36 +1396,42 @@ 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 }, } ); - System::set_block_number(9); + 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))); - System::set_block_number(15); + 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); }); } @@ -1277,12 +1441,12 @@ 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; - System::set_block_number(1); + go_to_block(1); Balances::make_free_balance_be(&Treasury::account_id(), parent_value * 3); Balances::make_free_balance_be(&parent_curator, parent_fee * 100); assert_ok!(Bounties::propose_bounty( @@ -1292,8 +1456,7 @@ fn accept_curator_handles_different_deposit_calculations() { )); assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), parent_index)); - System::set_block_number(2); - >::on_initialize(2); + go_to_block(2); assert_ok!(Bounties::propose_curator( RuntimeOrigin::root(), @@ -1307,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; @@ -1319,8 +1482,7 @@ fn accept_curator_handles_different_deposit_calculations() { child_value, b"12345-p1".to_vec() )); - System::set_block_number(3); - >::on_initialize(3); + go_to_block(3); assert_ok!(ChildBounties::propose_curator( RuntimeOrigin::signed(parent_curator), parent_index, @@ -1354,8 +1516,7 @@ fn accept_curator_handles_different_deposit_calculations() { child_value, b"12345-p1".to_vec() )); - System::set_block_number(4); - >::on_initialize(4); + go_to_block(4); assert_ok!(ChildBounties::propose_curator( RuntimeOrigin::signed(parent_curator), parent_index, @@ -1376,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; @@ -1387,8 +1548,7 @@ fn accept_curator_handles_different_deposit_calculations() { child_value, b"12345-p1".to_vec() )); - System::set_block_number(5); - >::on_initialize(5); + go_to_block(5); assert_ok!(ChildBounties::propose_curator( RuntimeOrigin::signed(parent_curator), parent_index, @@ -1412,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; @@ -1423,8 +1583,7 @@ fn accept_curator_handles_different_deposit_calculations() { child_value, b"12345-p1".to_vec() )); - System::set_block_number(5); - >::on_initialize(5); + go_to_block(5); assert_ok!(ChildBounties::propose_curator( RuntimeOrigin::signed(parent_curator), parent_index, @@ -1443,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/src/lib.rs b/substrate/frame/collective/src/lib.rs index 79428689caaf..8e533a7b2904 100644 --- a/substrate/frame/collective/src/lib.rs +++ b/substrate/frame/collective/src/lib.rs @@ -629,7 +629,7 @@ pub mod pallet { T::WeightInfo::execute( *length_bound, // B T::MaxMembers::get(), // M - ).saturating_add(proposal.get_dispatch_info().weight), // P + ).saturating_add(proposal.get_dispatch_info().call_weight), // P DispatchClass::Operational ))] pub fn execute( @@ -681,7 +681,7 @@ pub mod pallet { T::WeightInfo::propose_execute( *length_bound, // B T::MaxMembers::get(), // M - ).saturating_add(proposal.get_dispatch_info().weight) // P1 + ).saturating_add(proposal.get_dispatch_info().call_weight) // P1 } else { T::WeightInfo::propose_proposed( *length_bound, // B @@ -915,7 +915,7 @@ impl, I: 'static> Pallet { ) -> Result<(u32, DispatchResultWithPostInfo), DispatchError> { let proposal_len = proposal.encoded_size(); ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; ensure!( proposal_weight.all_lte(T::MaxProposalWeight::get()), Error::::WrongProposalWeight @@ -942,7 +942,7 @@ impl, I: 'static> Pallet { ) -> Result<(u32, u32), DispatchError> { let proposal_len = proposal.encoded_size(); ensure!(proposal_len <= length_bound as usize, Error::::WrongProposalLength); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; ensure!( proposal_weight.all_lte(T::MaxProposalWeight::get()), Error::::WrongProposalWeight @@ -1130,7 +1130,7 @@ impl, I: 'static> Pallet { storage::read(&key, &mut [0; 0], 0).ok_or(Error::::ProposalMissing)?; ensure!(proposal_len <= length_bound, Error::::WrongProposalLength); let proposal = ProposalOf::::get(hash).ok_or(Error::::ProposalMissing)?; - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; ensure!(proposal_weight.all_lte(weight_bound), Error::::WrongProposalWeight); Ok((proposal, proposal_len as usize)) } @@ -1157,7 +1157,7 @@ impl, I: 'static> Pallet { ) -> (Weight, u32) { Self::deposit_event(Event::Approved { proposal_hash }); - let dispatch_weight = proposal.get_dispatch_info().weight; + let dispatch_weight = proposal.get_dispatch_info().call_weight; let origin = RawOrigin::Members(yes_votes, seats).into(); let result = proposal.dispatch(origin); Self::deposit_event(Event::Executed { diff --git a/substrate/frame/collective/src/tests.rs b/substrate/frame/collective/src/tests.rs index 70ce221f10d0..c4ed17821ae8 100644 --- a/substrate/frame/collective/src/tests.rs +++ b/substrate/frame/collective/src/tests.rs @@ -36,7 +36,7 @@ use sp_runtime::{ }; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test @@ -316,7 +316,7 @@ fn close_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( @@ -388,7 +388,7 @@ fn proposal_weight_limit_works_on_approve() { old_count: MaxMembers::get(), }); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); // Set 1 as prime voter Prime::::set(Some(1)); @@ -430,7 +430,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { old_count: MaxMembers::get(), }); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( @@ -456,7 +456,7 @@ fn close_with_prime_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::set_members( RuntimeOrigin::root(), @@ -524,7 +524,7 @@ fn close_with_voting_prime_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::set_members( RuntimeOrigin::root(), @@ -594,7 +594,7 @@ fn close_with_no_prime_but_majority_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(CollectiveMajority::set_members( RuntimeOrigin::root(), @@ -874,7 +874,7 @@ fn correct_validate_and_get_proposal() { )); let hash = BlakeTwo256::hash_of(&proposal); - let weight = proposal.get_dispatch_info().weight; + let weight = proposal.get_dispatch_info().call_weight; assert_noop!( Collective::validate_and_get_proposal( &BlakeTwo256::hash_of(&vec![3; 4]), @@ -1073,7 +1073,7 @@ fn motions_all_first_vote_free_works() { // Test close() Extrinsics | Check DispatchResultWithPostInfo with Pay Info - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let close_rval: DispatchResultWithPostInfo = Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len); assert_eq!(close_rval.unwrap().pays_fee, Pays::No); @@ -1091,7 +1091,7 @@ fn motions_reproposing_disapproved_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( RuntimeOrigin::signed(1), @@ -1123,7 +1123,7 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { ExtBuilder::default().build_and_execute(|| { let proposal = RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {}); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash: H256 = proposal.blake2_256().into(); // The voting threshold is 2, but the required votes for `ExternalMajorityOrigin` is 3. // The proposal will be executed regardless of the voting threshold @@ -1253,7 +1253,7 @@ fn motions_disapproval_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( RuntimeOrigin::signed(1), @@ -1312,7 +1312,7 @@ fn motions_approval_works() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( RuntimeOrigin::signed(1), @@ -1373,7 +1373,7 @@ fn motion_with_no_votes_closes_with_disapproval() { ExtBuilder::default().build_and_execute(|| { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( RuntimeOrigin::signed(1), 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/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index 84ea7de00a2f..4aba1d24dbd5 100644 --- a/substrate/frame/contracts/proc-macro/src/lib.rs +++ b/substrate/frame/contracts/proc-macro/src/lib.rs @@ -522,7 +522,7 @@ fn expand_docs(def: &EnvDef) -> TokenStream2 { /// `expand_impls()`). fn expand_env(def: &EnvDef, docs: bool) -> TokenStream2 { let impls = expand_impls(def); - let docs = docs.then_some(expand_docs(def)).unwrap_or(TokenStream2::new()); + let docs = docs.then(|| expand_docs(def)).unwrap_or(TokenStream2::new()); let stable_api_count = def.host_funcs.iter().filter(|f| f.is_stable).count(); quote! { diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index 984e5712ae06..39f846ac4319 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -522,7 +522,7 @@ impl<'a, E: Ext + 'a> Runtime<'a, E> { run: impl FnOnce(&mut Self) -> DispatchResultWithPostInfo, ) -> Result { use frame_support::dispatch::extract_actual_weight; - let charged = self.charge_gas(runtime_cost(dispatch_info.weight))?; + let charged = self.charge_gas(runtime_cost(dispatch_info.call_weight))?; let result = run(self); let actual_weight = extract_actual_weight(&result, &dispatch_info); self.adjust_gas(charged, runtime_cost(actual_weight)); @@ -2347,7 +2347,7 @@ pub mod env { let execute_weight = <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); let weight = ctx.ext.gas_meter().gas_left().max(execute_weight); - let dispatch_info = DispatchInfo { weight, ..Default::default() }; + let dispatch_info = DispatchInfo { call_weight: weight, ..Default::default() }; ctx.call_dispatchable::( dispatch_info, 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/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/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/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 4e6812dee249..a443df7b20f5 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -124,7 +124,7 @@ impl DelegationMigrator for Pallet { /// Only used for testing. #[cfg(feature = "runtime-benchmarks")] - fn migrate_to_direct_staker(agent: Agent) { + fn force_kill_agent(agent: Agent) { >::remove(agent.clone().get()); >::iter() .filter(|(_, delegation)| delegation.agent == agent.clone().get()) @@ -136,8 +136,6 @@ impl DelegationMigrator for Pallet { ); >::remove(&delegator); }); - - T::CoreStaking::migrate_to_direct_staker(&agent.get()); } } diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 2c965e18b1b3..b7b82a43771e 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -676,7 +676,7 @@ mod staking_integration { // in equal parts. lets try to migrate this nominator into delegate based stake. // all balance currently is in 200 - assert_eq!(Balances::free_balance(agent), agent_amount); + assert_eq!(pallet_staking::asset::stakeable_balance::(&agent), agent_amount); // to migrate, nominator needs to set an account as a proxy delegator where staked funds // will be moved and delegated back to this old nominator account. This should be funded 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/src/benchmarking.rs b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs index 2a3994ff2aa6..222e79ab99c6 100644 --- a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs @@ -17,10 +17,9 @@ //! Two phase election pallet benchmarking. -use super::*; -use crate::{unsigned::IndexAssignmentOf, Pallet as MultiPhase}; -use frame_benchmarking::account; -use frame_election_provider_support::bounds::DataProviderBounds; +use core::cmp::Reverse; +use frame_benchmarking::{v2::*, BenchmarkError}; +use frame_election_provider_support::{bounds::DataProviderBounds, IndexAssignment}; use frame_support::{ assert_ok, traits::{Hooks, TryCollect}, @@ -31,6 +30,8 @@ use rand::{prelude::SliceRandom, rngs::SmallRng, SeedableRng}; use sp_arithmetic::{per_things::Percent, traits::One}; use sp_runtime::InnerOf; +use crate::{unsigned::IndexAssignmentOf, *}; + const SEED: u32 = 999; /// Creates a **valid** solution with exactly the given size. @@ -133,7 +134,7 @@ fn solution_with_size( .map(|(voter, _stake, votes)| { let percent_per_edge: InnerOf> = (100 / votes.len()).try_into().unwrap_or_else(|_| panic!("failed to convert")); - crate::unsigned::Assignment:: { + unsigned::Assignment:: { who: voter.clone(), distribution: votes .iter() @@ -190,140 +191,179 @@ fn set_up_data_provider(v: u32, t: u32) { }); } -frame_benchmarking::benchmarks! { - on_initialize_nothing { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn on_initialize_nothing() { assert!(CurrentPhase::::get().is_off()); - }: { - MultiPhase::::on_initialize(1u32.into()); - } verify { + + #[block] + { + Pallet::::on_initialize(1_u32.into()); + } + assert!(CurrentPhase::::get().is_off()); } - on_initialize_open_signed { + #[benchmark] + fn on_initialize_open_signed() { assert!(Snapshot::::get().is_none()); assert!(CurrentPhase::::get().is_off()); - }: { - MultiPhase::::phase_transition(Phase::Signed); - } verify { + + #[block] + { + Pallet::::phase_transition(Phase::Signed); + } + assert!(Snapshot::::get().is_none()); assert!(CurrentPhase::::get().is_signed()); } - on_initialize_open_unsigned { + #[benchmark] + fn on_initialize_open_unsigned() { assert!(Snapshot::::get().is_none()); assert!(CurrentPhase::::get().is_off()); - }: { - let now = frame_system::Pallet::::block_number(); - MultiPhase::::phase_transition(Phase::Unsigned((true, now))); - } verify { + + #[block] + { + let now = frame_system::Pallet::::block_number(); + Pallet::::phase_transition(Phase::Unsigned((true, now))); + } + assert!(Snapshot::::get().is_none()); assert!(CurrentPhase::::get().is_unsigned()); } - finalize_signed_phase_accept_solution { + #[benchmark] + fn finalize_signed_phase_accept_solution() { let receiver = account("receiver", 0, SEED); - let initial_balance = T::Currency::minimum_balance() + 10u32.into(); + let initial_balance = T::Currency::minimum_balance() + 10_u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); let ready = Default::default(); - let deposit: BalanceOf = 10u32.into(); + let deposit: BalanceOf = 10_u32.into(); let reward: BalanceOf = T::SignedRewardBase::get(); - let call_fee: BalanceOf = 30u32.into(); + let call_fee: BalanceOf = 30_u32.into(); assert_ok!(T::Currency::reserve(&receiver, deposit)); assert_eq!(T::Currency::free_balance(&receiver), T::Currency::minimum_balance()); - }: { - MultiPhase::::finalize_signed_phase_accept_solution( - ready, - &receiver, - deposit, - call_fee - ) - } verify { - assert_eq!( - T::Currency::free_balance(&receiver), - initial_balance + reward + call_fee - ); - assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); + + #[block] + { + Pallet::::finalize_signed_phase_accept_solution(ready, &receiver, deposit, call_fee); + } + + assert_eq!(T::Currency::free_balance(&receiver), initial_balance + reward + call_fee); + assert_eq!(T::Currency::reserved_balance(&receiver), 0_u32.into()); } - finalize_signed_phase_reject_solution { + #[benchmark] + fn finalize_signed_phase_reject_solution() { let receiver = account("receiver", 0, SEED); - let initial_balance = T::Currency::minimum_balance() + 10u32.into(); - let deposit: BalanceOf = 10u32.into(); + let initial_balance = T::Currency::minimum_balance() + 10_u32.into(); + let deposit: BalanceOf = 10_u32.into(); T::Currency::make_free_balance_be(&receiver, initial_balance); assert_ok!(T::Currency::reserve(&receiver, deposit)); assert_eq!(T::Currency::free_balance(&receiver), T::Currency::minimum_balance()); - assert_eq!(T::Currency::reserved_balance(&receiver), 10u32.into()); - }: { - MultiPhase::::finalize_signed_phase_reject_solution(&receiver, deposit) - } verify { + assert_eq!(T::Currency::reserved_balance(&receiver), 10_u32.into()); + + #[block] + { + Pallet::::finalize_signed_phase_reject_solution(&receiver, deposit) + } + assert_eq!(T::Currency::free_balance(&receiver), T::Currency::minimum_balance()); - assert_eq!(T::Currency::reserved_balance(&receiver), 0u32.into()); + assert_eq!(T::Currency::reserved_balance(&receiver), 0_u32.into()); } - create_snapshot_internal { - // number of votes in snapshot. - let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; - // number of targets in snapshot. - let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1]; - - // we don't directly need the data-provider to be populated, but it is just easy to use it. + #[benchmark] + fn create_snapshot_internal( + // Number of votes in snapshot. + v: Linear<{ T::BenchmarkingConfig::VOTERS[0] }, { T::BenchmarkingConfig::VOTERS[1] }>, + // Number of targets in snapshot. + t: Linear<{ T::BenchmarkingConfig::TARGETS[0] }, { T::BenchmarkingConfig::TARGETS[1] }>, + ) -> Result<(), BenchmarkError> { + // We don't directly need the data-provider to be populated, but it is just easy to use it. set_up_data_provider::(v, t); - // default bounds are unbounded. + // Default bounds are unbounded. let targets = T::DataProvider::electable_targets(DataProviderBounds::default())?; let voters = T::DataProvider::electing_voters(DataProviderBounds::default())?; let desired_targets = T::DataProvider::desired_targets()?; assert!(Snapshot::::get().is_none()); - }: { - MultiPhase::::create_snapshot_internal(targets, voters, desired_targets) - } verify { + + #[block] + { + Pallet::::create_snapshot_internal(targets, voters, desired_targets) + } + assert!(Snapshot::::get().is_some()); assert_eq!(SnapshotMetadata::::get().ok_or("metadata missing")?.voters, v); assert_eq!(SnapshotMetadata::::get().ok_or("metadata missing")?.targets, t); + + Ok(()) } - // a call to `::elect` where we only return the queued solution. - elect_queued { - // number of assignments, i.e. solution.len(). This means the active nominators, thus must be - // a subset of `v`. - let a in (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; - // number of desired targets. Must be a subset of `t`. - let d in (T::BenchmarkingConfig::DESIRED_TARGETS[0]) .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; - - // number of votes in snapshot. Not dominant. - let v = T::BenchmarkingConfig::VOTERS[1]; - // number of targets in snapshot. Not dominant. + // A call to `::elect` where we only return the queued solution. + #[benchmark] + fn elect_queued( + // Number of assignments, i.e. `solution.len()`. + // This means the active nominators, thus must be a subset of `v`. + a: Linear< + { T::BenchmarkingConfig::ACTIVE_VOTERS[0] }, + { T::BenchmarkingConfig::ACTIVE_VOTERS[1] }, + >, + // Number of desired targets. Must be a subset of `t`. + d: Linear< + { T::BenchmarkingConfig::DESIRED_TARGETS[0] }, + { T::BenchmarkingConfig::DESIRED_TARGETS[1] }, + >, + ) -> Result<(), BenchmarkError> { + // Number of votes in snapshot. Not dominant. + let v = T::BenchmarkingConfig::VOTERS[1]; + // Number of targets in snapshot. Not dominant. let t = T::BenchmarkingConfig::TARGETS[1]; let witness = SolutionOrSnapshotSize { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d)?; - let ready_solution = - MultiPhase::::feasibility_check(raw_solution, ElectionCompute::Signed) - .map_err(<&str>::from)?; + let ready_solution = Pallet::::feasibility_check(raw_solution, ElectionCompute::Signed) + .map_err(<&str>::from)?; CurrentPhase::::put(Phase::Signed); - // assume a queued solution is stored, regardless of where it comes from. + // Assume a queued solution is stored, regardless of where it comes from. QueuedSolution::::put(ready_solution); - // these are set by the `solution_with_size` function. + // These are set by the `solution_with_size` function. assert!(DesiredTargets::::get().is_some()); assert!(Snapshot::::get().is_some()); assert!(SnapshotMetadata::::get().is_some()); - }: { - assert_ok!( as ElectionProvider>::elect()); - } verify { + + let result; + + #[block] + { + result = as ElectionProvider>::elect(); + } + + assert!(result.is_ok()); assert!(QueuedSolution::::get().is_none()); assert!(DesiredTargets::::get().is_none()); assert!(Snapshot::::get().is_none()); assert!(SnapshotMetadata::::get().is_none()); - assert_eq!(CurrentPhase::::get(), >>::Off); + assert_eq!( + CurrentPhase::::get(), + >>::Off + ); + + Ok(()) } - submit { - // the queue is full and the solution is only better than the worse. - MultiPhase::::create_snapshot().map_err(<&str>::from)?; - MultiPhase::::phase_transition(Phase::Signed); + #[benchmark] + fn submit() -> Result<(), BenchmarkError> { + // The queue is full and the solution is only better than the worse. + Pallet::::create_snapshot().map_err(<&str>::from)?; + Pallet::::phase_transition(Phase::Signed); Round::::put(1); let mut signed_submissions = SignedSubmissions::::get(); @@ -331,7 +371,10 @@ frame_benchmarking::benchmarks! { // Insert `max` submissions for i in 0..(T::SignedMaxSubmissions::get() - 1) { let raw_solution = RawSolution { - score: ElectionScore { minimal_stake: 10_000_000u128 + (i as u128), ..Default::default() }, + score: ElectionScore { + minimal_stake: 10_000_000u128 + (i as u128), + ..Default::default() + }, ..Default::default() }; let signed_submission = SignedSubmission { @@ -344,67 +387,95 @@ frame_benchmarking::benchmarks! { } signed_submissions.put(); - // this score will eject the weakest one. + // This score will eject the weakest one. let solution = RawSolution { score: ElectionScore { minimal_stake: 10_000_000u128 + 1, ..Default::default() }, ..Default::default() }; let caller = frame_benchmarking::whitelisted_caller(); - let deposit = MultiPhase::::deposit_for( - &solution, - SnapshotMetadata::::get().unwrap_or_default(), + let deposit = + Pallet::::deposit_for(&solution, SnapshotMetadata::::get().unwrap_or_default()); + T::Currency::make_free_balance_be( + &caller, + T::Currency::minimum_balance() * 1000u32.into() + deposit, ); - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance() * 1000u32.into() + deposit); - }: _(RawOrigin::Signed(caller), Box::new(solution)) - verify { - assert!(MultiPhase::::signed_submissions().len() as u32 == T::SignedMaxSubmissions::get()); - } + #[extrinsic_call] + _(RawOrigin::Signed(caller), Box::new(solution)); - submit_unsigned { - // number of votes in snapshot. - let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; - // number of targets in snapshot. - let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1]; - // number of assignments, i.e. solution.len(). This means the active nominators, thus must be - // a subset of `v` component. - let a in - (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; - // number of desired targets. Must be a subset of `t` component. - let d in - (T::BenchmarkingConfig::DESIRED_TARGETS[0]) .. - T::BenchmarkingConfig::DESIRED_TARGETS[1]; + assert!(Pallet::::signed_submissions().len() as u32 == T::SignedMaxSubmissions::get()); + Ok(()) + } + + #[benchmark] + fn submit_unsigned( + // Number of votes in snapshot. + v: Linear<{ T::BenchmarkingConfig::VOTERS[0] }, { T::BenchmarkingConfig::VOTERS[1] }>, + // Number of targets in snapshot. + t: Linear<{ T::BenchmarkingConfig::TARGETS[0] }, { T::BenchmarkingConfig::TARGETS[1] }>, + // Number of assignments, i.e. `solution.len()`. + // This means the active nominators, thus must be a subset of `v` component. + a: Linear< + { T::BenchmarkingConfig::ACTIVE_VOTERS[0] }, + { T::BenchmarkingConfig::ACTIVE_VOTERS[1] }, + >, + // Number of desired targets. Must be a subset of `t` component. + d: Linear< + { T::BenchmarkingConfig::DESIRED_TARGETS[0] }, + { T::BenchmarkingConfig::DESIRED_TARGETS[1] }, + >, + ) -> Result<(), BenchmarkError> { let witness = SolutionOrSnapshotSize { voters: v, targets: t }; let raw_solution = solution_with_size::(witness, a, d)?; assert!(QueuedSolution::::get().is_none()); - CurrentPhase::::put(Phase::Unsigned((true, 1u32.into()))); - }: _(RawOrigin::None, Box::new(raw_solution), witness) - verify { + CurrentPhase::::put(Phase::Unsigned((true, 1_u32.into()))); + + #[extrinsic_call] + _(RawOrigin::None, Box::new(raw_solution), witness); + assert!(QueuedSolution::::get().is_some()); + + Ok(()) } // This is checking a valid solution. The worse case is indeed a valid solution. - feasibility_check { - // number of votes in snapshot. - let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; - // number of targets in snapshot. - let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1]; - // number of assignments, i.e. solution.len(). This means the active nominators, thus must be - // a subset of `v` component. - let a in (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; - // number of desired targets. Must be a subset of `t` component. - let d in (T::BenchmarkingConfig::DESIRED_TARGETS[0]) .. T::BenchmarkingConfig::DESIRED_TARGETS[1]; - + #[benchmark] + fn feasibility_check( + // Number of votes in snapshot. + v: Linear<{ T::BenchmarkingConfig::VOTERS[0] }, { T::BenchmarkingConfig::VOTERS[1] }>, + // Number of targets in snapshot. + t: Linear<{ T::BenchmarkingConfig::TARGETS[0] }, { T::BenchmarkingConfig::TARGETS[1] }>, + // Number of assignments, i.e. `solution.len()`. + // This means the active nominators, thus must be a subset of `v` component. + a: Linear< + { T::BenchmarkingConfig::ACTIVE_VOTERS[0] }, + { T::BenchmarkingConfig::ACTIVE_VOTERS[1] }, + >, + // Number of desired targets. Must be a subset of `t` component. + d: Linear< + { T::BenchmarkingConfig::DESIRED_TARGETS[0] }, + { T::BenchmarkingConfig::DESIRED_TARGETS[1] }, + >, + ) -> Result<(), BenchmarkError> { let size = SolutionOrSnapshotSize { voters: v, targets: t }; let raw_solution = solution_with_size::(size, a, d)?; assert_eq!(raw_solution.solution.voter_count() as u32, a); assert_eq!(raw_solution.solution.unique_targets().len() as u32, d); - }: { - assert!(MultiPhase::::feasibility_check(raw_solution, ElectionCompute::Unsigned).is_ok()); + + let result; + + #[block] + { + result = Pallet::::feasibility_check(raw_solution, ElectionCompute::Unsigned); + } + + assert!(result.is_ok()); + + Ok(()) } // NOTE: this weight is not used anywhere, but the fact that it should succeed when execution in @@ -419,20 +490,23 @@ frame_benchmarking::benchmarks! { // This benchmark is doing more work than a raw call to `OffchainWorker_offchain_worker` runtime // api call, since it is also setting up some mock data, which will itself exhaust the heap to // some extent. - #[extra] - mine_solution_offchain_memory { - // number of votes in snapshot. Fixed to maximum. + #[benchmark(extra)] + fn mine_solution_offchain_memory() { + // Number of votes in snapshot. Fixed to maximum. let v = T::BenchmarkingConfig::MINER_MAXIMUM_VOTERS; - // number of targets in snapshot. Fixed to maximum. + // Number of targets in snapshot. Fixed to maximum. let t = T::BenchmarkingConfig::MAXIMUM_TARGETS; set_up_data_provider::(v, t); let now = frame_system::Pallet::::block_number(); CurrentPhase::::put(Phase::Unsigned((true, now))); - MultiPhase::::create_snapshot().unwrap(); - }: { - // we can't really verify this as it won't write anything to state, check logs. - MultiPhase::::offchain_worker(now) + Pallet::::create_snapshot().unwrap(); + + #[block] + { + // we can't really verify this as it won't write anything to state, check logs. + Pallet::::offchain_worker(now) + } } // NOTE: this weight is not used anywhere, but the fact that it should succeed when execution in @@ -441,41 +515,48 @@ frame_benchmarking::benchmarks! { // numbers. // // ONLY run this benchmark in isolation, and pass the `--extra` flag to enable it. - #[extra] - create_snapshot_memory { - // number of votes in snapshot. Fixed to maximum. + #[benchmark(extra)] + fn create_snapshot_memory() -> Result<(), BenchmarkError> { + // Number of votes in snapshot. Fixed to maximum. let v = T::BenchmarkingConfig::SNAPSHOT_MAXIMUM_VOTERS; - // number of targets in snapshot. Fixed to maximum. + // Number of targets in snapshot. Fixed to maximum. let t = T::BenchmarkingConfig::MAXIMUM_TARGETS; set_up_data_provider::(v, t); assert!(Snapshot::::get().is_none()); - }: { - MultiPhase::::create_snapshot().map_err(|_| "could not create snapshot")?; - } verify { + + #[block] + { + Pallet::::create_snapshot().map_err(|_| "could not create snapshot")?; + } + assert!(Snapshot::::get().is_some()); assert_eq!(SnapshotMetadata::::get().ok_or("snapshot missing")?.voters, v); assert_eq!(SnapshotMetadata::::get().ok_or("snapshot missing")?.targets, t); - } - #[extra] - trim_assignments_length { - // number of votes in snapshot. - let v in (T::BenchmarkingConfig::VOTERS[0]) .. T::BenchmarkingConfig::VOTERS[1]; - // number of targets in snapshot. - let t in (T::BenchmarkingConfig::TARGETS[0]) .. T::BenchmarkingConfig::TARGETS[1]; - // number of assignments, i.e. solution.len(). This means the active nominators, thus must be - // a subset of `v` component. - let a in - (T::BenchmarkingConfig::ACTIVE_VOTERS[0]) .. T::BenchmarkingConfig::ACTIVE_VOTERS[1]; - // number of desired targets. Must be a subset of `t` component. - let d in - (T::BenchmarkingConfig::DESIRED_TARGETS[0]) .. - T::BenchmarkingConfig::DESIRED_TARGETS[1]; - // Subtract this percentage from the actual encoded size - let f in 0 .. 95; - use frame_election_provider_support::IndexAssignment; + Ok(()) + } + #[benchmark(extra)] + fn trim_assignments_length( + // Number of votes in snapshot. + v: Linear<{ T::BenchmarkingConfig::VOTERS[0] }, { T::BenchmarkingConfig::VOTERS[1] }>, + // Number of targets in snapshot. + t: Linear<{ T::BenchmarkingConfig::TARGETS[0] }, { T::BenchmarkingConfig::TARGETS[1] }>, + // Number of assignments, i.e. `solution.len()`. + // This means the active nominators, thus must be a subset of `v` component. + a: Linear< + { T::BenchmarkingConfig::ACTIVE_VOTERS[0] }, + { T::BenchmarkingConfig::ACTIVE_VOTERS[1] }, + >, + // Number of desired targets. Must be a subset of `t` component. + d: Linear< + { T::BenchmarkingConfig::DESIRED_TARGETS[0] }, + { T::BenchmarkingConfig::DESIRED_TARGETS[1] }, + >, + // Subtract this percentage from the actual encoded size. + f: Linear<0, 95>, + ) -> Result<(), BenchmarkError> { // Compute a random solution, then work backwards to get the lists of voters, targets, and // assignments let witness = SolutionOrSnapshotSize { voters: v, targets: t }; @@ -483,7 +564,9 @@ frame_benchmarking::benchmarks! { let RoundSnapshot { voters, targets } = Snapshot::::get().ok_or("snapshot missing")?; let voter_at = helpers::voter_at_fn::(&voters); let target_at = helpers::target_at_fn::(&targets); - let mut assignments = solution.into_assignment(voter_at, target_at).expect("solution generated by `solution_with_size` must be valid."); + let mut assignments = solution + .into_assignment(voter_at, target_at) + .expect("solution generated by `solution_with_size` must be valid."); // make a voter cache and some helper functions for access let cache = helpers::generate_voter_cache::(&voters); @@ -491,12 +574,15 @@ frame_benchmarking::benchmarks! { let target_index = helpers::target_index_fn::(&targets); // sort assignments by decreasing voter stake - assignments.sort_by_key(|crate::unsigned::Assignment:: { who, .. }| { - let stake = cache.get(who).map(|idx| { - let (_, stake, _) = voters[*idx]; - stake - }).unwrap_or_default(); - core::cmp::Reverse(stake) + assignments.sort_by_key(|unsigned::Assignment:: { who, .. }| { + let stake = cache + .get(who) + .map(|idx| { + let (_, stake, _) = voters[*idx]; + stake + }) + .unwrap_or_default(); + Reverse(stake) }); let mut index_assignments = assignments @@ -506,20 +592,26 @@ frame_benchmarking::benchmarks! { .unwrap(); let encoded_size_of = |assignments: &[IndexAssignmentOf]| { - SolutionOf::::try_from(assignments).map(|solution| solution.encoded_size()) + SolutionOf::::try_from(assignments) + .map(|solution| solution.encoded_size()) }; let desired_size = Percent::from_percent(100 - f.saturated_into::()) .mul_ceil(encoded_size_of(index_assignments.as_slice()).unwrap()); log!(trace, "desired_size = {}", desired_size); - }: { - crate::Miner::::trim_assignments_length( - desired_size.saturated_into(), - &mut index_assignments, - &encoded_size_of, - ).unwrap(); - } verify { - let solution = SolutionOf::::try_from(index_assignments.as_slice()).unwrap(); + + #[block] + { + Miner::::trim_assignments_length( + desired_size.saturated_into(), + &mut index_assignments, + &encoded_size_of, + ) + .unwrap(); + } + + let solution = + SolutionOf::::try_from(index_assignments.as_slice()).unwrap(); let encoding = solution.encode(); log!( trace, @@ -528,11 +620,13 @@ frame_benchmarking::benchmarks! { ); log!(trace, "actual encoded size = {}", encoding.len()); assert!(encoding.len() <= desired_size); + + Ok(()) } - impl_benchmark_test_suite!( - MultiPhase, - crate::mock::ExtBuilder::default().build_offchainify(10).0, - crate::mock::Runtime, - ); + impl_benchmark_test_suite! { + Pallet, + mock::ExtBuilder::default().build_offchainify(10).0, + mock::Runtime, + } } diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 072cfe176b61..06cb2963d762 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -245,7 +245,7 @@ use frame_support::{ weights::Weight, DefaultNoBound, EqNoBound, PartialEqNoBound, }; -use frame_system::{ensure_none, offchain::SendTransactionTypes, pallet_prelude::BlockNumberFor}; +use frame_system::{ensure_none, offchain::CreateInherent, pallet_prelude::BlockNumberFor}; use scale_info::TypeInfo; use sp_arithmetic::{ traits::{CheckedAdd, Zero}, @@ -576,7 +576,7 @@ pub mod pallet { use sp_runtime::traits::Convert; #[pallet::config] - pub trait Config: frame_system::Config + SendTransactionTypes> { + pub trait Config: frame_system::Config + CreateInherent> { type RuntimeEvent: From> + IsType<::RuntimeEvent> + TryInto>; diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 32a099e1a26f..2e5ac2527203 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -421,14 +421,23 @@ impl Convert> for Runtime { } } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } +} + pub type Extrinsic = sp_runtime::testing::TestXt; parameter_types! { diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 4c56f02db526..191131ed3acc 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -31,7 +31,10 @@ use frame_support::{ traits::{DefensiveResult, Get}, BoundedVec, }; -use frame_system::{offchain::SubmitTransaction, pallet_prelude::BlockNumberFor}; +use frame_system::{ + offchain::{CreateInherent, SubmitTransaction}, + pallet_prelude::BlockNumberFor, +}; use scale_info::TypeInfo; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult, @@ -179,7 +182,7 @@ fn ocw_solution_exists() -> bool { matches!(StorageValueRef::persistent(OFFCHAIN_CACHED_CALL).get::>(), Ok(Some(_))) } -impl Pallet { +impl>> Pallet { /// Mine a new npos solution. /// /// The Npos Solver type, `S`, must have the same AccountId and Error type as the @@ -277,7 +280,8 @@ impl Pallet { fn submit_call(call: Call) -> Result<(), MinerError> { log!(debug, "miner submitting a solution as an unsigned transaction"); - SubmitTransaction::>::submit_unsigned_transaction(call.into()) + let xt = T::create_inherent(call.into()); + SubmitTransaction::>::submit_transaction(xt) .map_err(|_| MinerError::PoolSubmissionFailed) } @@ -1818,7 +1822,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = codec::Decode::decode(&mut &*encoded).unwrap(); - let call = extrinsic.call; + let call = extrinsic.function; assert!(matches!(call, RuntimeCall::MultiPhase(Call::submit_unsigned { .. }))); }) } @@ -1835,7 +1839,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic = Extrinsic::decode(&mut &*encoded).unwrap(); - let call = match extrinsic.call { + let call = match extrinsic.function { RuntimeCall::MultiPhase(call @ Call::submit_unsigned { .. }) => call, _ => panic!("bad call: unexpected submission"), }; 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/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 0dc202ff2115..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); }); } @@ -322,24 +327,24 @@ fn automatic_unbonding_pools() { assert_eq!(::MaxUnbonding::get(), 1); // init state of pool members. - let init_free_balance_2 = Balances::free_balance(2); - let init_free_balance_3 = Balances::free_balance(3); + let init_stakeable_balance_2 = pallet_staking::asset::stakeable_balance::(&2); + let init_stakeable_balance_3 = pallet_staking::asset::stakeable_balance::(&3); let pool_bonded_account = Pools::generate_bonded_account(1); // creates a pool with 5 bonded, owned by 1. assert_ok!(Pools::create(RuntimeOrigin::signed(1), 5, 1, 1, 1)); - assert_eq!(locked_amount_for(pool_bonded_account), 5); + assert_eq!(staked_amount_for(pool_bonded_account), 5); let init_tvl = TotalValueLocked::::get(); // 2 joins the pool. assert_ok!(Pools::join(RuntimeOrigin::signed(2), 10, 1)); - assert_eq!(locked_amount_for(pool_bonded_account), 15); + assert_eq!(staked_amount_for(pool_bonded_account), 15); // 3 joins the pool. assert_ok!(Pools::join(RuntimeOrigin::signed(3), 10, 1)); - assert_eq!(locked_amount_for(pool_bonded_account), 25); + assert_eq!(staked_amount_for(pool_bonded_account), 25); assert_eq!(TotalValueLocked::::get(), 25); @@ -350,7 +355,7 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::unbond(RuntimeOrigin::signed(2), 2, 10)); // amount is still locked in the pool, needs to wait for unbonding period. - assert_eq!(locked_amount_for(pool_bonded_account), 25); + assert_eq!(staked_amount_for(pool_bonded_account), 25); // max chunks in the ledger are now filled up (`MaxUnlockingChunks == 1`). assert_eq!(unlocking_chunks_of(pool_bonded_account), 1); @@ -372,8 +377,8 @@ fn automatic_unbonding_pools() { assert_eq!(current_era(), 3); System::reset_events(); - let locked_before_withdraw_pool = locked_amount_for(pool_bonded_account); - assert_eq!(Balances::free_balance(pool_bonded_account), 26); + let staked_before_withdraw_pool = staked_amount_for(pool_bonded_account); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); // now unbonding 3 will work, although the pool's ledger still has the unlocking chunks // filled up. @@ -391,20 +396,21 @@ fn automatic_unbonding_pools() { ); // balance of the pool remains the same, it hasn't withdraw explicitly from the pool yet. - assert_eq!(Balances::free_balance(pool_bonded_account), 26); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); // but the locked amount in the pool's account decreases due to the auto-withdraw: - assert_eq!(locked_before_withdraw_pool - 10, locked_amount_for(pool_bonded_account)); + assert_eq!(staked_before_withdraw_pool - 10, staked_amount_for(pool_bonded_account)); // TVL correctly updated. assert_eq!(TotalValueLocked::::get(), 25 - 10); // however, note that the withdrawing from the pool still works for 2, the funds are taken - // from the pool's free balance. - assert_eq!(Balances::free_balance(pool_bonded_account), 26); + // from the pool's non staked balance. + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(pallet_staking::asset::staked::(&pool_bonded_account), 15); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); - assert_eq!(Balances::free_balance(pool_bonded_account), 16); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 16); - assert_eq!(Balances::free_balance(2), 20); + assert_eq!(pallet_staking::asset::stakeable_balance::(&2), 20); assert_eq!(TotalValueLocked::::get(), 15); // 3 cannot withdraw yet. @@ -423,9 +429,15 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10)); // final conditions are the expected. - assert_eq!(Balances::free_balance(pool_bonded_account), 6); // 5 init bonded + ED - assert_eq!(Balances::free_balance(2), init_free_balance_2); - assert_eq!(Balances::free_balance(3), init_free_balance_3); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED + assert_eq!( + pallet_staking::asset::stakeable_balance::(&2), + init_stakeable_balance_2 + ); + assert_eq!( + pallet_staking::asset::stakeable_balance::(&3), + init_stakeable_balance_3 + ); assert_eq!(TotalValueLocked::::get(), init_tvl); }); 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 e45452c1ddf9..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; @@ -61,7 +61,7 @@ pub const INIT_TIMESTAMP: BlockNumber = 30_000; pub const BLOCK_TIME: BlockNumber = 1000; type Block = frame_system::mocking::MockBlockU32; -type Extrinsic = testing::TestXt; +type Extrinsic = sp_runtime::testing::TestXt; frame_support::construct_runtime!( pub enum Runtime { @@ -304,18 +304,28 @@ 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; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } +} + pub struct OnChainSeqPhragmen; parameter_types! { @@ -687,7 +697,7 @@ pub fn roll_to_with_ocw(n: BlockNumber, pool: Arc>, delay_solu for encoded in &pool.read().transactions { let extrinsic = Extrinsic::decode(&mut &encoded[..]).unwrap(); - let _ = match extrinsic.call { + let _ = match extrinsic.function { RuntimeCall::ElectionProviderMultiPhase( call @ Call::submit_unsigned { .. }, ) => { @@ -797,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. @@ -853,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(), ); } @@ -915,9 +925,8 @@ pub(crate) fn set_minimum_election_score( .map_err(|_| ()) } -pub(crate) fn locked_amount_for(account_id: AccountId) -> Balance { - let lock = pallet_balances::Locks::::get(account_id); - lock[0].amount +pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance { + pallet_staking::asset::staked::(&account_id) } pub(crate) fn staking_events() -> Vec> { 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/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/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index a1c5f69e1b65..effbb6e786c0 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -1408,7 +1408,7 @@ mod tests { pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = - sp_runtime::generic::UncheckedExtrinsic; + sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test 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 ee0f8df29cf5..0c6ad5ef0978 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -25,12 +25,14 @@ pallet-example-offchain-worker = { workspace = true } pallet-example-split = { workspace = true } pallet-example-single-block-migrations = { workspace = true } pallet-example-tasks = { workspace = true } +pallet-example-authorization-tx-extension = { workspace = true } [features] default = ["std"] std = [ "pallet-default-config-example/std", "pallet-dev-mode/std", + "pallet-example-authorization-tx-extension/std", "pallet-example-basic/std", "pallet-example-frame-crate/std", "pallet-example-kitchensink/std", @@ -42,6 +44,7 @@ std = [ try-runtime = [ "pallet-default-config-example/try-runtime", "pallet-dev-mode/try-runtime", + "pallet-example-authorization-tx-extension/try-runtime", "pallet-example-basic/try-runtime", "pallet-example-kitchensink/try-runtime", "pallet-example-offchain-worker/try-runtime", diff --git a/substrate/frame/examples/authorization-tx-extension/Cargo.toml b/substrate/frame/examples/authorization-tx-extension/Cargo.toml new file mode 100644 index 000000000000..9b51fc6c1e63 --- /dev/null +++ b/substrate/frame/examples/authorization-tx-extension/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "pallet-example-authorization-tx-extension" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "MIT-0" +homepage.workspace = true +repository.workspace = true +description = "FRAME example authorization transaction extension pallet" +publish = false + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { 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 } + +sp-io = { workspace = true } +sp-runtime = { workspace = true } + +[dev-dependencies] +pallet-verify-signature = { workspace = true } +sp-core = { workspace = true } +sp-keyring = { workspace = true, default-features = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-verify-signature/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-verify-signature/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-verify-signature/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/examples/authorization-tx-extension/src/extensions.rs b/substrate/frame/examples/authorization-tx-extension/src/extensions.rs new file mode 100644 index 000000000000..dcbe171c183a --- /dev/null +++ b/substrate/frame/examples/authorization-tx-extension/src/extensions.rs @@ -0,0 +1,133 @@ +// 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 core::{fmt, marker::PhantomData}; + +use codec::{Decode, Encode}; +use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, Parameter}; +use scale_info::TypeInfo; +use sp_runtime::{ + impl_tx_ext_default, + traits::{ + DispatchInfoOf, DispatchOriginOf, IdentifyAccount, TransactionExtension, ValidateResult, + Verify, + }, + transaction_validity::{InvalidTransaction, ValidTransaction}, +}; + +use crate::pallet_coownership::{Config, Origin}; + +/// Helper struct to organize the data needed for signature verification of both parties involved. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +pub struct AuthCredentials { + first: (Signer, Signature), + second: (Signer, Signature), +} + +/// Extension that, if activated by providing a pair of signers and signatures, will authorize a +/// coowner origin of the two signers. Both signers have to construct their signatures on all of the +/// data that follows this extension in the `TransactionExtension` pipeline, their implications and +/// the call. Essentially re-sign the transaction from this point onwards in the pipeline by using +/// the `inherited_implication`, as shown below. +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct AuthorizeCoownership { + inner: Option>, + _phantom: PhantomData, +} + +impl Default for AuthorizeCoownership { + fn default() -> Self { + Self { inner: None, _phantom: Default::default() } + } +} + +impl AuthorizeCoownership { + /// Creates an active extension that will try to authorize the coownership origin. + pub fn new(first: (Signer, Signature), second: (Signer, Signature)) -> Self { + Self { inner: Some(AuthCredentials { first, second }), _phantom: Default::default() } + } +} + +impl fmt::Debug for AuthorizeCoownership { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "AuthorizeCoownership") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } +} + +impl TransactionExtension + for AuthorizeCoownership +where + Signer: IdentifyAccount + Parameter + Send + Sync + 'static, + Signature: Verify + Parameter + Send + Sync + 'static, +{ + const IDENTIFIER: &'static str = "AuthorizeCoownership"; + type Implicit = (); + type Val = (); + type Pre = (); + + fn validate( + &self, + mut origin: DispatchOriginOf, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _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 { + return Ok((ValidTransaction::default(), (), origin)); + }; + let first_account = auth.first.0.clone().into_account(); + let second_account = auth.second.0.clone().into_account(); + + // Construct the payload to sign using the `inherited_implication`. + let msg = inherited_implication.using_encoded(sp_io::hashing::blake2_256); + + // Both parties' signatures must be correct for the origin to be authorized. + // In a prod environment, we're just return a `InvalidTransaction::BadProof` if the + // signature isn't valid, but we return these custom errors to be able to assert them in + // tests. + if !auth.first.1.verify(&msg[..], &first_account) { + Err(InvalidTransaction::Custom(100))? + } + if !auth.second.1.verify(&msg[..], &second_account) { + Err(InvalidTransaction::Custom(200))? + } + // Construct a `pallet_coownership::Origin`. + let local_origin = Origin::Coowners(first_account, second_account); + // Turn it into a local `PalletsOrigin`. + let local_origin = ::PalletsOrigin::from(local_origin); + // Then finally into a pallet `RuntimeOrigin`. + let local_origin = ::RuntimeOrigin::from(local_origin); + // Which the `set_caller_from` function will convert into the overarching `RuntimeOrigin` + // created by `construct_runtime!`. + origin.set_caller_from(local_origin); + // Make sure to return the new origin. + Ok((ValidTransaction::default(), (), origin)) + } + // We're not doing any special logic in `TransactionExtension::prepare`, so just impl a default. + impl_tx_ext_default!(T::RuntimeCall; weight prepare); +} diff --git a/substrate/frame/examples/authorization-tx-extension/src/lib.rs b/substrate/frame/examples/authorization-tx-extension/src/lib.rs new file mode 100644 index 000000000000..9105155a94d0 --- /dev/null +++ b/substrate/frame/examples/authorization-tx-extension/src/lib.rs @@ -0,0 +1,158 @@ +// 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. + +//! # Authorization Transaction Extension Example Pallet +//! +//! **This pallet serves as an example and is not meant to be used in production.** +//! +//! FRAME Transaction Extension reference implementation, origin mutation, origin authorization and +//! integration in a `TransactionExtension` pipeline. +//! +//! The [TransactionExtension](sp_runtime::traits::TransactionExtension) used in this example is +//! [AuthorizeCoownership](extensions::AuthorizeCoownership). If activated, the extension will +//! authorize 2 signers as coowners, with a [coowner origin](pallet_coownership::Origin) specific to +//! the [coownership example pallet](pallet_coownership), by validating a signature of the rest of +//! the transaction from each party. This means any extensions after ours in the pipeline, their +//! implicits and the actual call. The extension pipeline used in our example checks the genesis +//! hash, transaction version and mortality of the transaction after the `AuthorizeCoownership` runs +//! as we want these transactions to run regardless of what origin passes through them and/or we +//! want their implicit data in any signature authorization happening earlier in the pipeline. +//! +//! In this example, aside from the [AuthorizeCoownership](extensions::AuthorizeCoownership) +//! extension, we use the following pallets: +//! - [pallet_coownership] - provides a coowner origin and the functionality to authorize it. +//! - [pallet_assets] - a dummy asset pallet that tracks assets, identified by an +//! [AssetId](pallet_assets::AssetId), and their respective owners, which can be either an +//! [account](pallet_assets::Owner::Single) or a [pair of owners](pallet_assets::Owner::Double). +//! +//! Assets are created in [pallet_assets] using the +//! [create_asset](pallet_assets::Call::create_asset) call, which accepts traditionally signed +//! origins (a single account) or coowner origins, authorized through the +//! [CoownerOrigin](pallet_assets::Config::CoownerOrigin) type. +//! +//! ### Example runtime setup +#![doc = docify::embed!("src/mock.rs", example_runtime)] +//! +//! ### Example usage +#![doc = docify::embed!("src/tests.rs", create_coowned_asset_works)] +//! +//! This example does not focus on any pallet logic or syntax, but rather on `TransactionExtension` +//! functionality. The pallets used are just skeletons to provide storage state and custom origin +//! choices and requirements, as shown in the examples. Any weight and/or +//! transaction fee is out of scope for this example. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod extensions; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +extern crate alloc; + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet_coownership { + use super::*; + use frame_support::traits::OriginTrait; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The aggregated origin which the dispatch will take. + type RuntimeOrigin: OriginTrait + + From + + IsType<::RuntimeOrigin>; + + /// The caller origin, overarching type of all pallets origins. + type PalletsOrigin: From> + TryInto, Error = Self::PalletsOrigin>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + /// Origin that this pallet can authorize. For the purposes of this example, it's just two + /// accounts that own something together. + #[pallet::origin] + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub enum Origin { + Coowners(T::AccountId, T::AccountId), + } +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet_assets { + use super::*; + + pub type AssetId = u32; + + /// Type that describes possible owners of a particular asset. + #[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub enum Owner { + Single(AccountId), + Double(AccountId, AccountId), + } + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Type that can authorize an account pair coowner origin. + type CoownerOrigin: EnsureOrigin< + Self::RuntimeOrigin, + Success = (Self::AccountId, Self::AccountId), + >; + } + + /// Map that holds the owner information for each asset it manages. + #[pallet::storage] + pub type AssetOwners = + StorageMap<_, Blake2_128Concat, AssetId, Owner<::AccountId>>; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::error] + pub enum Error { + /// Asset already exists. + AlreadyExists, + } + + #[pallet::call] + impl Pallet { + /// Simple call that just creates an asset with a specific `AssetId`. This call will fail if + /// there is already an asset with the same `AssetId`. + /// + /// The origin is either a single account (traditionally signed origin) or a coowner origin. + #[pallet::call_index(0)] + pub fn create_asset(origin: OriginFor, asset_id: AssetId) -> DispatchResult { + let owner: Owner = match T::CoownerOrigin::try_origin(origin) { + Ok((first, second)) => Owner::Double(first, second), + Err(origin) => ensure_signed(origin).map(|account| Owner::Single(account))?, + }; + AssetOwners::::try_mutate(asset_id, |maybe_owner| { + if maybe_owner.is_some() { + return Err(Error::::AlreadyExists); + } + *maybe_owner = Some(owner); + Ok(()) + })?; + Ok(()) + } + } +} diff --git a/substrate/frame/examples/authorization-tx-extension/src/mock.rs b/substrate/frame/examples/authorization-tx-extension/src/mock.rs new file mode 100644 index 000000000000..aa70d12d7d84 --- /dev/null +++ b/substrate/frame/examples/authorization-tx-extension/src/mock.rs @@ -0,0 +1,142 @@ +// 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 crate::*; +pub(crate) use example_runtime::*; +use extensions::AuthorizeCoownership; +use frame_support::derive_impl; +use frame_system::{CheckEra, CheckGenesis, CheckNonce, CheckTxVersion}; +use pallet_verify_signature::VerifySignature; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + BuildStorage, MultiSignature, MultiSigner, +}; + +#[docify::export] +mod example_runtime { + use super::*; + + /// Our `TransactionExtension` fit for general transactions. + pub type TxExtension = ( + // Validate the signature of regular account transactions (substitutes the old signed + // transaction). + VerifySignature, + // Nonce check (and increment) for the caller. + CheckNonce, + // If activated, will mutate the origin to a `pallet_coownership` origin of 2 accounts that + // own something. + AuthorizeCoownership, + // Some other extensions that we want to run for every possible origin and we want captured + // in any and all signature and authorization schemes (such as the traditional account + // signature or the double signature in `pallet_coownership`). + CheckGenesis, + CheckTxVersion, + CheckEra, + ); + /// Convenience type to more easily construct the signature to be signed in case + /// `AuthorizeCoownership` is activated. + pub type InnerTxExtension = (CheckGenesis, CheckTxVersion, CheckEra); + pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; + pub type Header = generic::Header; + pub type Block = generic::Block; + pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + pub type Signature = MultiSignature; + pub type BlockNumber = u32; + + // For testing the pallet, we construct a mock runtime. + frame_support::construct_runtime!( + pub enum Runtime + { + System: frame_system, + VerifySignaturePallet: pallet_verify_signature, + + Assets: pallet_assets, + Coownership: pallet_coownership, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] + impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Block = Block; + type Lookup = IdentityLookup; + } + + #[cfg(feature = "runtime-benchmarks")] + pub struct BenchmarkHelper; + #[cfg(feature = "runtime-benchmarks")] + impl pallet_verify_signature::BenchmarkHelper for BenchmarkHelper { + fn create_signature(_entropy: &[u8], msg: &[u8]) -> (MultiSignature, AccountId) { + use sp_io::crypto::{sr25519_generate, sr25519_sign}; + use sp_runtime::traits::IdentifyAccount; + let public = sr25519_generate(0.into(), None); + let who_account: AccountId = MultiSigner::Sr25519(public).into_account().into(); + let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &public, msg).unwrap()); + (signature, who_account) + } + } + + impl pallet_verify_signature::Config for Runtime { + type Signature = MultiSignature; + type AccountIdentifier = MultiSigner; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; + } + + /// Type that enables any pallet to ask for a coowner origin. + pub struct EnsureCoowner; + impl EnsureOrigin for EnsureCoowner { + type Success = (AccountId, AccountId); + + fn try_origin(o: RuntimeOrigin) -> Result { + match o.clone().into() { + Ok(pallet_coownership::Origin::::Coowners(first, second)) => + Ok((first, second)), + _ => Err(o), + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + unimplemented!() + } + } + + impl pallet_assets::Config for Runtime { + type CoownerOrigin = EnsureCoowner; + } + + impl pallet_coownership::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + } +} + +// 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 t = RuntimeGenesisConfig { + // We use default for brevity, but you can configure as desired if needed. + system: Default::default(), + } + .build_storage() + .unwrap(); + t.into() +} diff --git a/substrate/frame/examples/authorization-tx-extension/src/tests.rs b/substrate/frame/examples/authorization-tx-extension/src/tests.rs new file mode 100644 index 000000000000..8ca35c099556 --- /dev/null +++ b/substrate/frame/examples/authorization-tx-extension/src/tests.rs @@ -0,0 +1,274 @@ +// 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. + +//! Tests for pallet-example-authorization-tx-extension. + +use codec::Encode; +use frame_support::{ + assert_noop, + dispatch::GetDispatchInfo, + pallet_prelude::{InvalidTransaction, TransactionValidityError}, +}; +use pallet_verify_signature::VerifySignature; +use sp_keyring::AccountKeyring; +use sp_runtime::{ + generic::ExtensionVersion, + traits::{Applyable, Checkable, IdentityLookup, TransactionExtension}, + MultiSignature, MultiSigner, +}; + +use crate::{extensions::AuthorizeCoownership, mock::*, pallet_assets}; + +#[test] +fn create_asset_works() { + new_test_ext().execute_with(|| { + let alice_keyring = AccountKeyring::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 = ( + frame_system::CheckNonce::::from(initial_nonce), + AuthorizeCoownership::::default(), + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create the transaction signature, to be used in the top level `VerifyMultiSignature` + // extension. + let tx_sign = MultiSignature::Sr25519( + (&(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. + let tx_ext = ( + VerifySignature::new_with_signature(tx_sign, alice_account.clone()), + frame_system::CheckNonce::::from(initial_nonce), + AuthorizeCoownership::::default(), + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create the transaction and we're ready for dispatch. + let uxt = UncheckedExtrinsic::new_transaction(create_asset_call, tx_ext); + // Check Extrinsic validity and apply it. + let uxt_info = uxt.get_dispatch_info(); + let uxt_len = uxt.using_encoded(|e| e.len()); + // Manually pay for Alice's nonce. + frame_system::Account::::mutate(&alice_account, |info| { + info.nonce = initial_nonce; + info.providers = 1; + }); + // Check should pass. + let xt = >>::check( + uxt, + &Default::default(), + ) + .unwrap(); + // Apply the extrinsic. + let res = xt.apply::(&uxt_info, uxt_len).unwrap(); + + // Asserting the results. + assert_eq!(frame_system::Account::::get(&alice_account).nonce, initial_nonce + 1); + assert_eq!( + pallet_assets::AssetOwners::::get(42), + Some(pallet_assets::Owner::::Single(alice_account)) + ); + assert!(res.is_ok()); + }); +} + +#[docify::export] +#[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_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(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create the payload Alice and Bob need to sign. + 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))), + ); + // Create Bob's signature. + let bob_inner_sig = MultiSignature::Sr25519( + inner_payload.using_encoded(|e| bob_keyring.sign(&sp_io::hashing::blake2_256(e))), + ); + // Create the transaction extension, to be signed by the submitter of the extrinsic, let's + // have it be Charlie. + let initial_nonce = 23; + let tx_ext = ( + frame_system::CheckNonce::::from(initial_nonce), + AuthorizeCoownership::::new( + (alice_keyring.into(), alice_inner_sig.clone()), + (bob_keyring.into(), bob_inner_sig.clone()), + ), + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create Charlie's transaction signature, to be used in the top level + // `VerifyMultiSignature` extension. + let tx_sign = MultiSignature::Sr25519( + (&(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. + let tx_ext = ( + VerifySignature::new_with_signature(tx_sign, charlie_account.clone()), + frame_system::CheckNonce::::from(initial_nonce), + AuthorizeCoownership::::new( + (alice_keyring.into(), alice_inner_sig), + (bob_keyring.into(), bob_inner_sig), + ), + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create the transaction and we're ready for dispatch. + let uxt = UncheckedExtrinsic::new_transaction(create_asset_call, tx_ext); + // Check Extrinsic validity and apply it. + let uxt_info = uxt.get_dispatch_info(); + let uxt_len = uxt.using_encoded(|e| e.len()); + // Manually pay for Charlie's nonce. + frame_system::Account::::mutate(&charlie_account, |info| { + info.nonce = initial_nonce; + info.providers = 1; + }); + // Check should pass. + let xt = >>::check( + uxt, + &Default::default(), + ) + .unwrap(); + // Apply the extrinsic. + let res = xt.apply::(&uxt_info, uxt_len).unwrap(); + + // Asserting the results. + assert!(res.is_ok()); + assert_eq!(frame_system::Account::::get(charlie_account).nonce, initial_nonce + 1); + assert_eq!( + pallet_assets::AssetOwners::::get(42), + Some(pallet_assets::Owner::::Double(alice_account, bob_account)) + ); + }); +} + +#[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 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 = ( + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + // Sign with mortal era check. + frame_system::CheckEra::::from(sp_runtime::generic::Era::mortal(4, 0)), + ); + // Create the payload Alice and Bob need to sign. + let inner_payload = (&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))), + ); + // Create Bob's signature. + let bob_inner_sig = MultiSignature::Sr25519( + inner_payload.using_encoded(|e| bob_keyring.sign(&sp_io::hashing::blake2_256(e))), + ); + // Create the transaction extension, to be signed by the submitter of the extrinsic, let's + // have it be Charlie. + let initial_nonce = 23; + let tx_ext = ( + frame_system::CheckNonce::::from(initial_nonce), + AuthorizeCoownership::::new( + (alice_keyring.into(), alice_inner_sig.clone()), + (bob_keyring.into(), bob_inner_sig.clone()), + ), + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + // Construct the transaction as immortal with a different era check. + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create Charlie's transaction signature, to be used in the top level + // `VerifyMultiSignature` extension. + let tx_sign = MultiSignature::Sr25519( + (&(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. + let tx_ext = ( + VerifySignature::new_with_signature(tx_sign, charlie_account.clone()), + frame_system::CheckNonce::::from(initial_nonce), + AuthorizeCoownership::::new( + (alice_keyring.into(), alice_inner_sig), + (bob_keyring.into(), bob_inner_sig), + ), + frame_system::CheckGenesis::::new(), + frame_system::CheckTxVersion::::new(), + // Construct the transaction as immortal with a different era check. + frame_system::CheckEra::::from(sp_runtime::generic::Era::immortal()), + ); + // Create the transaction and we're ready for dispatch. + let uxt = UncheckedExtrinsic::new_transaction(create_asset_call, tx_ext); + // Check Extrinsic validity and apply it. + let uxt_info = uxt.get_dispatch_info(); + let uxt_len = uxt.using_encoded(|e| e.len()); + // Manually pay for Charlie's nonce. + frame_system::Account::::mutate(charlie_account, |info| { + info.nonce = initial_nonce; + info.providers = 1; + }); + // Check should pass. + let xt = >>::check( + uxt, + &Default::default(), + ) + .unwrap(); + // The extrinsic should fail as the signature for the `AuthorizeCoownership` doesn't work + // for the provided payload with the changed transaction mortality. + assert_noop!( + xt.apply::(&uxt_info, uxt_len), + TransactionValidityError::Invalid(InvalidTransaction::Custom(100)) + ); + }); +} diff --git a/substrate/frame/examples/basic/src/lib.rs b/substrate/frame/examples/basic/src/lib.rs index fea04cb447a0..efdf4332e329 100644 --- a/substrate/frame/examples/basic/src/lib.rs +++ b/substrate/frame/examples/basic/src/lib.rs @@ -46,9 +46,10 @@ //! use the [`Config::WeightInfo`] trait to calculate call weights. This can also be overridden, //! as demonstrated by [`Call::set_dummy`]. //! - A private function that performs a storage update. -//! - A simple signed extension implementation (see: [`sp_runtime::traits::SignedExtension`]) which -//! increases the priority of the [`Call::set_dummy`] if it's present and drops any transaction -//! with an encoded length higher than 200 bytes. +//! - A simple transaction extension implementation (see: +//! [`sp_runtime::traits::TransactionExtension`]) which increases the priority of the +//! [`Call::set_dummy`] if it's present and drops any transaction with an encoded length higher +//! than 200 bytes. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -60,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, }; @@ -67,10 +69,12 @@ use frame_system::ensure_signed; use log::info; use scale_info::TypeInfo; use sp_runtime::{ - traits::{Bounded, DispatchInfoOf, SaturatedConversion, Saturating, SignedExtension}, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + impl_tx_ext_default, + traits::{ + Bounded, DispatchInfoOf, DispatchOriginOf, SaturatedConversion, Saturating, + TransactionExtension, ValidateResult, }, + transaction_validity::{InvalidTransaction, ValidTransaction}, }; // Re-export pallet items so that they can be accessed from the crate namespace. @@ -440,42 +444,43 @@ impl Pallet { } } -// Similar to other FRAME pallets, your pallet can also define a signed extension and perform some -// checks and [pre/post]processing [before/after] the transaction. A signed extension can be any -// decodable type that implements `SignedExtension`. See the trait definition for the full list of -// bounds. As a convention, you can follow this approach to create an extension for your pallet: +// Similar to other FRAME pallets, your pallet can also define a transaction extension and perform +// some checks and [pre/post]processing [before/after] the transaction. A transaction extension can +// be any decodable type that implements `TransactionExtension`. See the trait definition for the +// full list of bounds. As a convention, you can follow this approach to create an extension for +// your pallet: // - If the extension does not carry any data, then use a tuple struct with just a `marker` // (needed for the compiler to accept `T: Config`) will suffice. // - Otherwise, create a tuple struct which contains the external data. Of course, for the entire // struct to be decodable, each individual item also needs to be decodable. // -// Note that a signed extension can also indicate that a particular data must be present in the -// _signing payload_ of a transaction by providing an implementation for the `additional_signed` -// method. This example will not cover this type of extension. See `CheckSpecVersion` in -// [FRAME System](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/system#signed-extensions) +// Note that a transaction extension can also indicate that a particular data must be present in the +// _signing payload_ of a transaction by providing an implementation for the `implicit` method. This +// example will not cover this type of extension. See `CheckSpecVersion` in [FRAME +// System](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/system#signed-extensions) // for an example. // // Using the extension, you can add some hooks to the life cycle of each transaction. Note that by // default, an extension is applied to all `Call` functions (i.e. all transactions). the `Call` enum -// variant is given to each function of `SignedExtension`. Hence, you can filter based on pallet or -// a particular call if needed. +// variant is given to each function of `TransactionExtension`. Hence, you can filter based on +// pallet or a particular call if needed. // // Some extra information, such as encoded length, some static dispatch info like weight and the // sender of the transaction (if signed) are also provided. // -// The full list of hooks that can be added to a signed extension can be found -// [here](https://paritytech.github.io/polkadot-sdk/master/sp_runtime/traits/trait.SignedExtension.html). +// The full list of hooks that can be added to a transaction extension can be found in the +// `TransactionExtension` trait definition. // -// The signed extensions are aggregated in the runtime file of a substrate chain. All extensions -// should be aggregated in a tuple and passed to the `CheckedExtrinsic` and `UncheckedExtrinsic` -// types defined in the runtime. Lookup `pub type SignedExtra = (...)` in `node/runtime` and -// `node-template` for an example of this. +// The transaction extensions are aggregated in the runtime file of a substrate chain. All +// extensions should be aggregated in a tuple and passed to the `CheckedExtrinsic` and +// `UncheckedExtrinsic` types defined in the runtime. Lookup `pub type TxExtension = (...)` in +// `node/runtime` and `node-template` for an example of this. -/// A simple signed extension that checks for the `set_dummy` call. In that case, it increases the -/// priority and prints some log. +/// A simple transaction extension that checks for the `set_dummy` call. In that case, it increases +/// the priority and prints some log. /// /// Additionally, it drops any transaction with an encoded length higher than 200 bytes. No -/// particular reason why, just to demonstrate the power of signed extensions. +/// particular reason why, just to demonstrate the power of transaction extensions. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct WatchDummy(PhantomData); @@ -486,52 +491,43 @@ impl core::fmt::Debug for WatchDummy { } } -impl SignedExtension for WatchDummy +impl TransactionExtension<::RuntimeCall> + for WatchDummy where ::RuntimeCall: IsSubType>, { const IDENTIFIER: &'static str = "WatchDummy"; - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); type Pre = (); - - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) - } + type Val = (); fn validate( &self, - _who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: DispatchOriginOf<::RuntimeCall>, + call: &::RuntimeCall, + _info: &DispatchInfoOf<::RuntimeCall>, len: usize, - ) -> TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> ValidateResult::RuntimeCall> { // if the transaction is too big, just drop it. if len > 200 { - return InvalidTransaction::ExhaustsResources.into() + return Err(InvalidTransaction::ExhaustsResources.into()) } // check for `set_dummy` - match call.is_sub_type() { + let validity = match call.is_sub_type() { Some(Call::set_dummy { .. }) => { sp_runtime::print("set_dummy was received."); let valid_tx = ValidTransaction { priority: Bounded::max_value(), ..Default::default() }; - Ok(valid_tx) + valid_tx }, - _ => Ok(Default::default()), - } + _ => Default::default(), + }; + Ok((validity, (), origin)) } + impl_tx_ext_default!(::RuntimeCall; weight prepare); } diff --git a/substrate/frame/examples/basic/src/tests.rs b/substrate/frame/examples/basic/src/tests.rs index d7095eb3c944..5ec253ebecf4 100644 --- a/substrate/frame/examples/basic/src/tests.rs +++ b/substrate/frame/examples/basic/src/tests.rs @@ -27,7 +27,8 @@ use sp_core::H256; // 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 sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, DispatchTransaction, IdentityLookup}, + transaction_validity::TransactionSource::External, BuildStorage, }; // Reexport crate as its pallet name for construct_runtime. @@ -146,13 +147,16 @@ fn signed_ext_watch_dummy_works() { assert_eq!( WatchDummy::(PhantomData) - .validate(&1, &call, &info, 150) + .validate_only(Some(1).into(), &call, &info, 150, External, 0) .unwrap() + .0 .priority, u64::MAX, ); assert_eq!( - WatchDummy::(PhantomData).validate(&1, &call, &info, 250), + WatchDummy::(PhantomData) + .validate_only(Some(1).into(), &call, &info, 250, External, 0) + .unwrap_err(), InvalidTransaction::ExhaustsResources.into(), ); }) @@ -174,13 +178,13 @@ fn weights_work() { let info1 = default_call.get_dispatch_info(); // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` // TODO: account for proof size weight - assert!(info1.weight.ref_time() > 0); - assert_eq!(info1.weight, ::WeightInfo::accumulate_dummy()); + assert!(info1.call_weight.ref_time() > 0); + assert_eq!(info1.call_weight, ::WeightInfo::accumulate_dummy()); // `set_dummy` is simpler than `accumulate_dummy`, and the weight // should be less. let custom_call = pallet_example_basic::Call::::set_dummy { new_value: 20 }; let info2 = custom_call.get_dispatch_info(); // TODO: account for proof size weight - assert!(info1.weight.ref_time() > info2.weight.ref_time()); + assert!(info1.call_weight.ref_time() > info2.call_weight.ref_time()); } 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/src/lib.rs b/substrate/frame/examples/offchain-worker/src/lib.rs index add014f6b34a..b3fdb6ea1897 100644 --- a/substrate/frame/examples/offchain-worker/src/lib.rs +++ b/substrate/frame/examples/offchain-worker/src/lib.rs @@ -53,8 +53,8 @@ use frame_support::traits::Get; use frame_system::{ self as system, offchain::{ - AppCrypto, CreateSignedTransaction, SendSignedTransaction, SendUnsignedTransaction, - SignedPayload, Signer, SigningTypes, SubmitTransaction, + AppCrypto, CreateInherent, CreateSignedTransaction, SendSignedTransaction, + SendUnsignedTransaction, SignedPayload, Signer, SigningTypes, SubmitTransaction, }, pallet_prelude::BlockNumberFor, }; @@ -124,7 +124,9 @@ pub mod pallet { /// This pallet's configuration trait #[pallet::config] - pub trait Config: CreateSignedTransaction> + frame_system::Config { + pub trait Config: + CreateSignedTransaction> + CreateInherent> + frame_system::Config + { /// The identifier type for an offchain worker. type AuthorityId: AppCrypto; @@ -501,7 +503,8 @@ impl Pallet { // implement unsigned validation logic, as any mistakes can lead to opening DoS or spam // attack vectors. See validation logic docs for more details. // - SubmitTransaction::>::submit_unsigned_transaction(call.into()) + let xt = T::create_inherent(call.into()); + SubmitTransaction::>::submit_transaction(xt) .map_err(|()| "Unable to submit unsigned transaction.")?; Ok(()) diff --git a/substrate/frame/examples/offchain-worker/src/tests.rs b/substrate/frame/examples/offchain-worker/src/tests.rs index 741adbe6d26a..df5cf02594f6 100644 --- a/substrate/frame/examples/offchain-worker/src/tests.rs +++ b/substrate/frame/examples/offchain-worker/src/tests.rs @@ -31,7 +31,7 @@ use sp_core::{ use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; use sp_runtime::{ testing::TestXt, - traits::{BlakeTwo256, Extrinsic as ExtrinsicT, IdentifyAccount, IdentityLookup, Verify}, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, RuntimeAppPublic, }; @@ -80,25 +80,47 @@ impl frame_system::offchain::SigningTypes for Test { type Signature = Signature; } -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } +impl frame_system::offchain::CreateTransaction for Test +where + RuntimeCall: From, +{ + type Extension = (); + + fn create_transaction(call: RuntimeCall, _extension: Self::Extension) -> Extrinsic { + Extrinsic::new_transaction(call, ()) + } +} + impl frame_system::offchain::CreateSignedTransaction for Test where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, _public: ::Signer, _account: AccountId, nonce: u64, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { - Some((call, (nonce, ()))) + ) -> Option { + Some(Extrinsic::new_signed(call, nonce, (), ())) + } +} + +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) } } @@ -218,8 +240,8 @@ 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_eq!(tx.signature.unwrap().0, 0); - assert_eq!(tx.call, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); + assert!(matches!(tx.preamble, sp_runtime::generic::Preamble::Signed(0, (), (),))); + assert_eq!(tx.function, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); }); } @@ -258,11 +280,11 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { // then let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert_eq!(tx.signature, None); + assert!(tx.is_inherent()); if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, - }) = tx.call + }) = tx.function { assert_eq!(body, price_payload); @@ -313,11 +335,11 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { // then let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert_eq!(tx.signature, None); + assert!(tx.is_inherent()); if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, - }) = tx.call + }) = tx.function { assert_eq!(body, price_payload); @@ -354,9 +376,9 @@ fn should_submit_raw_unsigned_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_eq!(tx.signature, None); + assert!(tx.is_inherent()); assert_eq!( - tx.call, + tx.function, RuntimeCall::Example(crate::Call::submit_price_unsigned { block_number: 1, price: 15523 diff --git a/substrate/frame/examples/src/lib.rs b/substrate/frame/examples/src/lib.rs index dee23a41379f..d0d30830f2f0 100644 --- a/substrate/frame/examples/src/lib.rs +++ b/substrate/frame/examples/src/lib.rs @@ -40,12 +40,16 @@ //! - [`pallet_example_split`]: A simple example of a FRAME pallet demonstrating the ability to //! split sections across multiple files. //! -//! - [`pallet_example_frame_crate`]: Example pallet showcasing how one can be -//! built using only the `frame` umbrella crate. +//! - [`pallet_example_frame_crate`]: Example pallet showcasing how one can be built using only the +//! `frame` umbrella crate. //! //! - [`pallet_example_single_block_migrations`]: An example pallet demonstrating best-practices for //! writing storage migrations. //! //! - [`pallet_example_tasks`]: This pallet demonstrates the use of `Tasks` to execute service work. //! +//! - [`pallet_example_authorization_tx_extension`]: An example `TransactionExtension` that +//! authorizes a custom origin through signature validation, along with two support pallets to +//! showcase the usage. +//! //! **Tip**: Use `cargo doc --package --open` to view each pallet's documentation. diff --git a/substrate/frame/examples/tasks/src/lib.rs b/substrate/frame/examples/tasks/src/lib.rs index 1908a235ba15..7d51617497d6 100644 --- a/substrate/frame/examples/tasks/src/lib.rs +++ b/substrate/frame/examples/tasks/src/lib.rs @@ -19,7 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::dispatch::DispatchResult; -use frame_system::offchain::SendTransactionTypes; +use frame_system::offchain::CreateInherent; #[cfg(feature = "experimental")] use frame_system::offchain::SubmitTransaction; // Re-export pallet items so that they can be accessed from the crate namespace. @@ -77,22 +77,21 @@ pub mod pallet { let call = frame_system::Call::::do_task { task: runtime_task.into() }; // Submit the task as an unsigned transaction - let res = - SubmitTransaction::>::submit_unsigned_transaction( - call.into(), - ); + let xt = >>::create_inherent(call.into()); + let res = SubmitTransaction::>::submit_transaction(xt); match res { Ok(_) => log::info!(target: LOG_TARGET, "Submitted the task."), Err(e) => log::error!(target: LOG_TARGET, "Error submitting task: {:?}", e), } } } + + #[cfg(not(feature = "experimental"))] + fn offchain_worker(_block_number: BlockNumberFor) {} } #[pallet::config] - pub trait Config: - SendTransactionTypes> + frame_system::Config - { + pub trait Config: CreateInherent> + frame_system::Config { type RuntimeTask: frame_support::traits::Task + IsType<::RuntimeTask> + From>; diff --git a/substrate/frame/examples/tasks/src/mock.rs b/substrate/frame/examples/tasks/src/mock.rs index 33912bb5269c..3dc9153c94a0 100644 --- a/substrate/frame/examples/tasks/src/mock.rs +++ b/substrate/frame/examples/tasks/src/mock.rs @@ -18,7 +18,7 @@ //! Mock runtime for `tasks-example` tests. #![cfg(test)] -use crate::{self as tasks_example}; +use crate::{self as pallet_example_tasks}; use frame_support::derive_impl; use sp_runtime::testing::TestXt; @@ -29,7 +29,7 @@ type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Runtime { System: frame_system, - TasksExample: tasks_example, + TasksExample: pallet_example_tasks, } ); @@ -40,15 +40,24 @@ impl frame_system::Config for Runtime { type Block = Block; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } -impl tasks_example::Config for Runtime { +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } +} + +impl pallet_example_tasks::Config for Runtime { type RuntimeTask = RuntimeTask; type WeightInfo = (); } diff --git a/substrate/frame/examples/tasks/src/tests.rs b/substrate/frame/examples/tasks/src/tests.rs index 6c8acb0194bd..4b31849c2ea9 100644 --- a/substrate/frame/examples/tasks/src/tests.rs +++ b/substrate/frame/examples/tasks/src/tests.rs @@ -157,6 +157,7 @@ fn task_with_offchain_worker() { let tx = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx = Extrinsic::decode(&mut &*tx).unwrap(); - assert_eq!(tx.signature, None); + use sp_runtime::traits::ExtrinsicLike; + assert!(tx.is_bare()); }); } diff --git a/substrate/frame/examples/tasks/src/weights.rs b/substrate/frame/examples/tasks/src/weights.rs index 793af6e96220..c9ddea6f9a8a 100644 --- a/substrate/frame/examples/tasks/src/weights.rs +++ b/substrate/frame/examples/tasks/src/weights.rs @@ -15,30 +15,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for `pallet_example_tasks` +//! Autogenerated weights for `tasks_example` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-02, STEPS: `20`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `MacBook.local`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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/node-template +// ./target/production/substrate-node // benchmark // pallet -// --chain -// dev -// --pallet -// pallet_example_tasks -// --extrinsic -// * -// --steps -// 20 -// --repeat -// 10 -// --output -// frame/examples/tasks/src/weights.rs +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=tasks_example +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/examples/tasks/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,37 +49,42 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_template. +/// Weight functions needed for `tasks_example`. pub trait WeightInfo { fn add_number_into_total() -> Weight; } -/// Weight functions for `pallet_example_kitchensink`. +/// Weights for `tasks_example` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: Kitchensink OtherFoo (r:0 w:1) - /// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TasksExample::Numbers` (r:1 w:1) + /// Proof: `TasksExample::Numbers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TasksExample::Total` (r:1 w:1) + /// Proof: `TasksExample::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn add_number_into_total() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `149` + // Estimated: `3614` + // Minimum execution time: 5_776_000 picoseconds. + Weight::from_parts(6_178_000, 3614) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: Kitchensink OtherFoo (r:0 w:1) - /// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: `TasksExample::Numbers` (r:1 w:1) + /// Proof: `TasksExample::Numbers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TasksExample::Total` (r:1 w:1) + /// Proof: `TasksExample::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn add_number_into_total() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 1_000_000 picoseconds. - Weight::from_parts(1_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) + // Measured: `149` + // Estimated: `3614` + // Minimum execution time: 5_776_000 picoseconds. + Weight::from_parts(6_178_000, 3614) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/executive/src/tests.rs b/substrate/frame/executive/src/tests.rs index 69a970a89d93..3841b010325b 100644 --- a/substrate/frame/executive/src/tests.rs +++ b/substrate/frame/executive/src/tests.rs @@ -24,7 +24,7 @@ use sp_core::H256; use sp_runtime::{ generic::{DigestItem, Era}, testing::{Block, Digest, Header}, - traits::{Block as BlockT, Header as HeaderT}, + traits::{Block as BlockT, Header as HeaderT, TransactionExtension}, transaction_validity::{ InvalidTransaction, TransactionValidityError, UnknownTransaction, ValidTransaction, }, @@ -309,6 +309,34 @@ parameter_types! { }; } +pub struct MockExtensionsWeights; +impl frame_system::ExtensionsWeightInfo for MockExtensionsWeights { + fn check_genesis() -> Weight { + Weight::zero() + } + fn check_mortality_mortal_transaction() -> Weight { + Weight::from_parts(10, 0) + } + fn check_mortality_immortal_transaction() -> Weight { + Weight::from_parts(10, 0) + } + fn check_non_zero_sender() -> Weight { + Weight::zero() + } + fn check_nonce() -> Weight { + Weight::from_parts(10, 0) + } + fn check_spec_version() -> Weight { + Weight::zero() + } + fn check_tx_version() -> Weight { + Weight::zero() + } + fn check_weight() -> Weight { + Weight::from_parts(10, 0) + } +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type BlockWeights = BlockWeights; @@ -323,6 +351,7 @@ impl frame_system::Config for Runtime { type PostInherents = MockedSystemCallbacks; type PostTransactions = MockedSystemCallbacks; type MultiBlockMigrator = MockedModeGetter; + type ExtensionsWeightInfo = MockExtensionsWeights; } #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, MaxEncodedLen, TypeInfo, RuntimeDebug)] @@ -336,15 +365,60 @@ impl VariantCount for FreezeReasonId { type Balance = u64; +pub struct BalancesWeights; +impl pallet_balances::WeightInfo for BalancesWeights { + fn transfer_allow_death() -> Weight { + Weight::from_parts(25, 0) + } + fn transfer_keep_alive() -> Weight { + Weight::zero() + } + fn force_set_balance_creating() -> Weight { + Weight::zero() + } + fn force_set_balance_killing() -> Weight { + Weight::zero() + } + fn force_transfer() -> Weight { + Weight::zero() + } + fn transfer_all() -> Weight { + Weight::zero() + } + fn force_unreserve() -> Weight { + Weight::zero() + } + fn upgrade_accounts(_u: u32) -> Weight { + Weight::zero() + } + fn force_adjust_total_issuance() -> Weight { + Weight::zero() + } + fn burn_allow_death() -> Weight { + Weight::zero() + } + fn burn_keep_alive() -> Weight { + Weight::zero() + } +} + #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { type Balance = Balance; type AccountStore = System; + type WeightInfo = BalancesWeights; type RuntimeFreezeReason = FreezeReasonId; type FreezeIdentifier = FreezeReasonId; type MaxFreezes = VariantCountOf; } +pub struct MockTxPaymentWeights; +impl pallet_transaction_payment::WeightInfo for MockTxPaymentWeights { + fn charge_transaction_payment() -> Weight { + Weight::from_parts(10, 0) + } +} + parameter_types! { pub const TransactionByteFee: Balance = 0; } @@ -355,6 +429,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = IdentityFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); + type WeightInfo = MockTxPaymentWeights; } impl custom::Config for Runtime {} @@ -372,14 +447,19 @@ parameter_types! { Default::default(); } -type SignedExtra = ( +type TxExtension = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); -type TestXt = sp_runtime::testing::TestXt; -type TestBlock = Block; +type UncheckedXt = sp_runtime::generic::UncheckedExtrinsic< + u64, + RuntimeCall, + sp_runtime::testing::UintAuthorityId, + TxExtension, +>; +type TestBlock = Block; // Will contain `true` when the custom runtime logic was called. const CUSTOM_ON_RUNTIME_KEY: &[u8] = b":custom:on_runtime"; @@ -399,7 +479,7 @@ impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { type Executive = super::Executive< Runtime, - Block, + Block, ChainContext, Runtime, AllPalletsWithSystem, @@ -474,17 +554,14 @@ impl MultiStepMigrator for MockedModeGetter { } } -fn extra(nonce: u64, fee: Balance) -> SignedExtra { +fn tx_ext(nonce: u64, fee: Balance) -> TxExtension { ( frame_system::CheckEra::from(Era::Immortal), frame_system::CheckNonce::from(nonce), frame_system::CheckWeight::new(), pallet_transaction_payment::ChargeTransactionPayment::from(fee), ) -} - -fn sign_extra(who: u64, nonce: u64, fee: Balance) -> Option<(u64, SignedExtra)> { - Some((who, extra(nonce, fee))) + .into() } fn call_transfer(dest: u64, value: u64) -> RuntimeCall { @@ -497,8 +574,8 @@ fn balance_transfer_dispatch_works() { pallet_balances::GenesisConfig:: { balances: vec![(1, 211)] } .assimilate_storage(&mut t) .unwrap(); - let xt = TestXt::new(call_transfer(2, 69), sign_extra(1, 0, 0)); - let weight = xt.get_dispatch_info().weight + + let xt = UncheckedXt::new_signed(call_transfer(2, 69), 1, 1.into(), tx_ext(0, 0)); + let weight = xt.get_dispatch_info().total_weight() + ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; @@ -608,7 +685,7 @@ fn block_import_of_bad_extrinsic_root_fails() { fn bad_extrinsic_not_inserted() { let mut t = new_test_ext(1); // bad nonce check! - let xt = TestXt::new(call_transfer(33, 69), sign_extra(1, 30, 0)); + let xt = UncheckedXt::new_signed(call_transfer(33, 69), 1, 1.into(), tx_ext(30, 0)); t.execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); assert_err!( @@ -622,35 +699,47 @@ fn bad_extrinsic_not_inserted() { #[test] fn block_weight_limit_enforced() { let mut t = new_test_ext(10000); - // given: TestXt uses the encoded len as fixed Len: - let xt = TestXt::new( - RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), - ); - let encoded = xt.encode(); - let encoded_len = encoded.len() as u64; + let transfer_weight = + <::WeightInfo as pallet_balances::WeightInfo>::transfer_allow_death(); + let extension_weight = tx_ext(0u32.into(), 0) + .weight(&RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 })); // on_initialize weight + base block execution weight let block_weights = ::BlockWeights::get(); let base_block_weight = Weight::from_parts(175, 0) + block_weights.base_block; let limit = block_weights.get(DispatchClass::Normal).max_total.unwrap() - base_block_weight; - let num_to_exhaust_block = limit.ref_time() / (encoded_len + 5); + let num_to_exhaust_block = + limit.ref_time() / (transfer_weight.ref_time() + extension_weight.ref_time() + 5); t.execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); // Base block execution weight + `on_initialize` weight from the custom module. assert_eq!(>::block_weight().total(), base_block_weight); for nonce in 0..=num_to_exhaust_block { - let xt = TestXt::new( + let xt = UncheckedXt::new_signed( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, nonce.into(), 0), + 1, + 1.into(), + tx_ext(nonce.into(), 0), ); + let encoded = xt.encode(); + let encoded_len = encoded.len() as u64; let res = Executive::apply_extrinsic(xt); if nonce != num_to_exhaust_block { assert!(res.is_ok()); assert_eq!( >::block_weight().total(), - //--------------------- on_initialize + block_execution + extrinsic_base weight + extrinsic len - Weight::from_parts((encoded_len + 5) * (nonce + 1), (nonce + 1)* encoded_len) + base_block_weight, + //--------------------- + // on_initialize + // + block_execution + // + extrinsic_base weight + // + call weight + // + extension weight + // + extrinsic len + Weight::from_parts( + (transfer_weight.ref_time() + extension_weight.ref_time() + 5) * + (nonce + 1), + (nonce + 1) * encoded_len + ) + base_block_weight, ); assert_eq!( >::extrinsic_index(), @@ -665,20 +754,28 @@ fn block_weight_limit_enforced() { #[test] fn block_weight_and_size_is_stored_per_tx() { - let xt = TestXt::new( + let xt = UncheckedXt::new_signed( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), + 1, + 1.into(), + tx_ext(0, 0), ); - let x1 = TestXt::new( + let x1 = UncheckedXt::new_signed( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 1, 0), + 1, + 1.into(), + tx_ext(1, 0), ); - let x2 = TestXt::new( + let x2 = UncheckedXt::new_signed( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 2, 0), + 1, + 1.into(), + tx_ext(2, 0), ); let len = xt.clone().encode().len() as u32; - let mut t = new_test_ext(1); + let extension_weight = xt.extension_weight(); + let transfer_weight = <::WeightInfo as pallet_balances::WeightInfo>::transfer_allow_death(); + let mut t = new_test_ext(2); t.execute_with(|| { // Block execution weight + on_initialize weight from custom module let base_block_weight = Weight::from_parts(175, 0) + @@ -693,8 +790,8 @@ fn block_weight_and_size_is_stored_per_tx() { assert!(Executive::apply_extrinsic(x1.clone()).unwrap().is_ok()); assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); - // default weight for `TestXt` == encoded length. - let extrinsic_weight = Weight::from_parts(len as u64, 0) + + let extrinsic_weight = transfer_weight + + extension_weight + ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; @@ -720,8 +817,8 @@ fn block_weight_and_size_is_stored_per_tx() { #[test] fn validate_unsigned() { - let valid = TestXt::new(RuntimeCall::Custom(custom::Call::allowed_unsigned {}), None); - let invalid = TestXt::new(RuntimeCall::Custom(custom::Call::unallowed_unsigned {}), None); + let valid = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::allowed_unsigned {})); + let invalid = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::unallowed_unsigned {})); let mut t = new_test_ext(1); t.execute_with(|| { @@ -762,9 +859,11 @@ fn can_not_pay_for_tx_fee_on_full_lock() { 110, ) .unwrap(); - let xt = TestXt::new( + let xt = UncheckedXt::new_signed( RuntimeCall::System(frame_system::Call::remark { remark: vec![1u8] }), - sign_extra(1, 0, 0), + 1, + 1.into(), + tx_ext(0, 0), ); Executive::initialize_block(&Header::new_from_number(1)); @@ -889,9 +988,11 @@ fn event_from_runtime_upgrade_is_included() { /// used through the `ExecuteBlock` trait. #[test] fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { - let xt = TestXt::new( + let xt = UncheckedXt::new_signed( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), + 1, + 1.into(), + tx_ext(0, 0), ); let header = new_test_ext(1).execute_with(|| { @@ -919,7 +1020,10 @@ fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); - >>::execute_block(Block::new(header, vec![xt])); + >>::execute_block(Block::new( + header, + vec![xt], + )); assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module"); assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode()); @@ -985,7 +1089,7 @@ fn offchain_worker_works_as_expected() { #[test] fn calculating_storage_root_twice_works() { let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); - let xt = TestXt::new(call, sign_extra(1, 0, 0)); + let xt = UncheckedXt::new_signed(call, 1, 1.into(), tx_ext(0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1004,11 +1108,13 @@ fn calculating_storage_root_twice_works() { #[test] #[should_panic(expected = "Invalid inherent position for extrinsic at index 1")] fn invalid_inherent_position_fail() { - let xt1 = TestXt::new( + let xt1 = UncheckedXt::new_signed( RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 33, value: 0 }), - sign_extra(1, 0, 0), + 1, + 1.into(), + tx_ext(0, 0), ); - let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt2 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1027,8 +1133,8 @@ fn invalid_inherent_position_fail() { #[test] fn valid_inherents_position_works() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1048,7 +1154,12 @@ fn valid_inherents_position_works() { #[test] #[should_panic(expected = "A call was labelled as mandatory, but resulted in an Error.")] fn invalid_inherents_fail_block_execution() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), sign_extra(1, 0, 0)); + let xt1 = UncheckedXt::new_signed( + RuntimeCall::Custom(custom::Call::inherent {}), + 1, + 1.into(), + tx_ext(0, 0), + ); new_test_ext(1).execute_with(|| { Executive::execute_block(Block::new( @@ -1061,7 +1172,7 @@ fn invalid_inherents_fail_block_execution() { // Inherents are created by the runtime and don't need to be validated. #[test] fn inherents_fail_validate_block() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); new_test_ext(1).execute_with(|| { assert_eq!( @@ -1075,7 +1186,7 @@ fn inherents_fail_validate_block() { /// Inherents still work while `initialize_block` forbids transactions. #[test] fn inherents_ok_while_exts_forbidden_works() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1095,8 +1206,8 @@ fn inherents_ok_while_exts_forbidden_works() { #[test] #[should_panic = "Only inherents are allowed in this block"] fn transactions_in_only_inherents_block_errors() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1116,8 +1227,8 @@ fn transactions_in_only_inherents_block_errors() { /// Same as above but no error. #[test] fn transactions_in_normal_block_works() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1137,8 +1248,8 @@ fn transactions_in_normal_block_works() { #[test] #[cfg(feature = "try-runtime")] fn try_execute_block_works() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); let header = new_test_ext(1).execute_with(|| { Executive::initialize_block(&Header::new_from_number(1)); @@ -1165,8 +1276,8 @@ fn try_execute_block_works() { #[cfg(feature = "try-runtime")] #[should_panic = "Only inherents allowed"] fn try_execute_tx_forbidden_errors() { - let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let xt1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1193,9 +1304,9 @@ fn try_execute_tx_forbidden_errors() { /// Check that `ensure_inherents_are_first` reports the correct indices. #[test] fn ensure_inherents_are_first_works() { - let in1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None); - let in2 = TestXt::new(RuntimeCall::Custom2(custom2::Call::inherent {}), None); - let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let in1 = UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})); + let in2 = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); + let xt2 = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); // Mocked empty header: let header = new_test_ext(1).execute_with(|| { @@ -1273,18 +1384,20 @@ fn callbacks_in_block_execution_works_inner(mbms_active: bool) { for i in 0..n_in { let xt = if i % 2 == 0 { - TestXt::new(RuntimeCall::Custom(custom::Call::inherent {}), None) + UncheckedXt::new_bare(RuntimeCall::Custom(custom::Call::inherent {})) } else { - TestXt::new(RuntimeCall::Custom2(custom2::Call::optional_inherent {}), None) + UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})) }; Executive::apply_extrinsic(xt.clone()).unwrap().unwrap(); extrinsics.push(xt); } for t in 0..n_tx { - let xt = TestXt::new( + let xt = UncheckedXt::new_signed( RuntimeCall::Custom2(custom2::Call::some_call {}), - sign_extra(1, t as u64, 0), + 1, + 1.into(), + tx_ext(t as u64, 0), ); // Extrinsics can be applied even when MBMs are active. Only the `execute_block` // will reject it. @@ -1324,8 +1437,13 @@ fn callbacks_in_block_execution_works_inner(mbms_active: bool) { #[test] fn post_inherent_called_after_all_inherents() { - let in1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::inherent {}), None); - let xt1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::some_call {}), sign_extra(1, 0, 0)); + let in1 = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); + let xt1 = UncheckedXt::new_signed( + RuntimeCall::Custom2(custom2::Call::some_call {}), + 1, + 1.into(), + tx_ext(0, 0), + ); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1359,8 +1477,13 @@ fn post_inherent_called_after_all_inherents() { /// Regression test for AppSec finding #40. #[test] fn post_inherent_called_after_all_optional_inherents() { - let in1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::optional_inherent {}), None); - let xt1 = TestXt::new(RuntimeCall::Custom2(custom2::Call::some_call {}), sign_extra(1, 0, 0)); + let in1 = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})); + let xt1 = UncheckedXt::new_signed( + RuntimeCall::Custom2(custom2::Call::some_call {}), + 1, + 1.into(), + tx_ext(0, 0), + ); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1393,14 +1516,14 @@ fn post_inherent_called_after_all_optional_inherents() { #[test] fn is_inherent_works() { - let ext = TestXt::new(RuntimeCall::Custom2(custom2::Call::inherent {}), None); + let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::inherent {})); assert!(Runtime::is_inherent(&ext)); - let ext = TestXt::new(RuntimeCall::Custom2(custom2::Call::optional_inherent {}), None); + let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::optional_inherent {})); assert!(Runtime::is_inherent(&ext)); - let ext = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); + let ext = UncheckedXt::new_signed(call_transfer(33, 0), 1, 1.into(), tx_ext(0, 0)); assert!(!Runtime::is_inherent(&ext)); - let ext = TestXt::new(RuntimeCall::Custom2(custom2::Call::allowed_unsigned {}), None); + let ext = UncheckedXt::new_bare(RuntimeCall::Custom2(custom2::Call::allowed_unsigned {})); assert!(!Runtime::is_inherent(&ext), "Unsigned ext are not automatically inherents"); } 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/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 77128872f285..7c11f381ca10 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -137,15 +137,16 @@ fn deregister_works() { ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(1); - assert_eq!(::Currency::reserved_balance(&1), 0); + // reserved balance prior to registering for fast unstake. + let pre_reserved = ::Currency::reserved_balance(&1); // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, Deposit::get()); // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); @@ -243,7 +244,8 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given - assert_eq!(::Currency::reserved_balance(&1), 0); + // reserved balance prior to registering for fast unstake. + let pre_reserved = ::Currency::reserved_balance(&1); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(3))); @@ -251,7 +253,10 @@ mod on_idle { assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(7))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(9))); - assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); + assert_eq!( + ::Currency::reserved_balance(&1) - pre_reserved, + Deposit::get() + ); assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -279,6 +284,9 @@ mod on_idle { // when next_block(true); + // pre_reserve may change due to unstaked amount. + let pre_reserved = ::Currency::reserved_balance(&1); + // then assert_eq!( Head::::get(), @@ -289,7 +297,7 @@ mod on_idle { ); assert_eq!(Queue::::count(), 3); - assert_eq!(::Currency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); assert_eq!( fast_unstake_events_since_last_call(), 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/src/benchmarking.rs b/substrate/frame/glutton/src/benchmarking.rs index 0b1309e63304..b5fbbd4cd200 100644 --- a/substrate/frame/glutton/src/benchmarking.rs +++ b/substrate/frame/glutton/src/benchmarking.rs @@ -20,80 +20,122 @@ //! Has to be compiled and run twice to calibrate on new hardware. #[cfg(feature = "runtime-benchmarks")] -use super::*; - -use frame_benchmarking::benchmarks; +use frame_benchmarking::v2::*; use frame_support::{pallet_prelude::*, weights::constants::*}; -use frame_system::RawOrigin as SystemOrigin; +use frame_system::RawOrigin; use sp_runtime::{traits::One, Perbill}; -use crate::Pallet as Glutton; -use frame_system::Pallet as System; +use crate::*; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn initialize_pallet_grow(n: Linear<0, 1_000>) -> Result<(), BenchmarkError> { + #[block] + { + Pallet::::initialize_pallet(RawOrigin::Root.into(), n, None)?; + } -benchmarks! { - initialize_pallet_grow { - let n in 0 .. 1_000; - }: { - Glutton::::initialize_pallet(SystemOrigin::Root.into(), n, None).unwrap() - } verify { assert_eq!(TrashDataCount::::get(), n); + + Ok(()) } - initialize_pallet_shrink { - let n in 0 .. 1_000; + #[benchmark] + fn initialize_pallet_shrink(n: Linear<0, 1_000>) -> Result<(), BenchmarkError> { + Pallet::::initialize_pallet(RawOrigin::Root.into(), n, None)?; + + #[block] + { + Pallet::::initialize_pallet(RawOrigin::Root.into(), 0, Some(n))?; + } - Glutton::::initialize_pallet(SystemOrigin::Root.into(), n, None).unwrap(); - }: { - Glutton::::initialize_pallet(SystemOrigin::Root.into(), 0, Some(n)).unwrap() - } verify { assert_eq!(TrashDataCount::::get(), 0); - } - waste_ref_time_iter { - let i in 0..100_000; - }: { - Glutton::::waste_ref_time_iter(vec![0u8; 64], i); + Ok(()) } - waste_proof_size_some { - let i in 0..5_000; + #[benchmark] + fn waste_ref_time_iter(i: Linear<0, 100_000>) { + #[block] + { + Pallet::::waste_ref_time_iter(vec![0u8; 64], i); + } + } + #[benchmark] + fn waste_proof_size_some(i: Linear<0, 5_000>) { (0..5000).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); - }: { - (0..i).for_each(|i| { - TrashData::::get(i); - }) + + #[block] + { + (0..i).for_each(|i| { + TrashData::::get(i); + }) + } } // For manual verification only. - on_idle_high_proof_waste { + #[benchmark] + fn on_idle_high_proof_waste() { (0..5000).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); - let _ = Glutton::::set_compute(SystemOrigin::Root.into(), One::one()); - let _ = Glutton::::set_storage(SystemOrigin::Root.into(), One::one()); - }: { - let weight = Glutton::::on_idle(System::::block_number(), Weight::from_parts(WEIGHT_REF_TIME_PER_MILLIS * 100, WEIGHT_PROOF_SIZE_PER_MB * 5)); + let _ = Pallet::::set_compute(RawOrigin::Root.into(), One::one()); + let _ = Pallet::::set_storage(RawOrigin::Root.into(), One::one()); + + #[block] + { + Pallet::::on_idle( + frame_system::Pallet::::block_number(), + Weight::from_parts(WEIGHT_REF_TIME_PER_MILLIS * 100, WEIGHT_PROOF_SIZE_PER_MB * 5), + ); + } } // For manual verification only. - on_idle_low_proof_waste { + #[benchmark] + fn on_idle_low_proof_waste() { (0..5000).for_each(|i| TrashData::::insert(i, [i as u8; 1024])); - let _ = Glutton::::set_compute(SystemOrigin::Root.into(), One::one()); - let _ = Glutton::::set_storage(SystemOrigin::Root.into(), One::one()); - }: { - let weight = Glutton::::on_idle(System::::block_number(), Weight::from_parts(WEIGHT_REF_TIME_PER_MILLIS * 100, WEIGHT_PROOF_SIZE_PER_KB * 20)); + let _ = Pallet::::set_compute(RawOrigin::Root.into(), One::one()); + let _ = Pallet::::set_storage(RawOrigin::Root.into(), One::one()); + + #[block] + { + Pallet::::on_idle( + frame_system::Pallet::::block_number(), + Weight::from_parts(WEIGHT_REF_TIME_PER_MILLIS * 100, WEIGHT_PROOF_SIZE_PER_KB * 20), + ); + } } - empty_on_idle { - }: { + #[benchmark] + fn empty_on_idle() { // Enough weight to do nothing. - Glutton::::on_idle(System::::block_number(), T::WeightInfo::empty_on_idle()); + #[block] + { + Pallet::::on_idle( + frame_system::Pallet::::block_number(), + T::WeightInfo::empty_on_idle(), + ); + } } - set_compute { - }: _(SystemOrigin::Root, FixedU64::from_perbill(Perbill::from_percent(50))) + #[benchmark] + fn set_compute() { + #[extrinsic_call] + _(RawOrigin::Root, FixedU64::from_perbill(Perbill::from_percent(50))); + } - set_storage { - }: _(SystemOrigin::Root, FixedU64::from_perbill(Perbill::from_percent(50))) + #[benchmark] + fn set_storage() { + #[extrinsic_call] + _(RawOrigin::Root, FixedU64::from_perbill(Perbill::from_percent(50))); + } - impl_benchmark_test_suite!(Glutton, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite! { + Pallet, + mock::new_test_ext(), + mock::Test + } } 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/src/benchmarking.rs b/substrate/frame/grandpa/src/benchmarking.rs index c89592b3b359..0a10e5882776 100644 --- a/substrate/frame/grandpa/src/benchmarking.rs +++ b/substrate/frame/grandpa/src/benchmarking.rs @@ -18,54 +18,57 @@ //! Benchmarks for the GRANDPA pallet. use super::{Pallet as Grandpa, *}; -use frame_benchmarking::v1::benchmarks; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; use sp_core::H256; -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 should be deterministic since the keys we use are static. // with the current benchmark setup it is not possible to generate this // programmatically from the benchmark setup. const EQUIVOCATION_PROOF_BLOB: [u8; 257] = [ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 136, 220, 52, 23, - 213, 5, 142, 196, 180, 80, 62, 12, 18, 234, 26, 10, 137, 190, 32, - 15, 233, 137, 34, 66, 61, 67, 52, 1, 79, 166, 176, 238, 207, 48, - 195, 55, 171, 225, 252, 130, 161, 56, 151, 29, 193, 32, 25, 157, - 249, 39, 80, 193, 214, 96, 167, 147, 25, 130, 45, 42, 64, 208, 182, - 164, 10, 0, 0, 0, 0, 0, 0, 0, 234, 236, 231, 45, 70, 171, 135, 246, - 136, 153, 38, 167, 91, 134, 150, 242, 215, 83, 56, 238, 16, 119, 55, - 170, 32, 69, 255, 248, 164, 20, 57, 50, 122, 115, 135, 96, 80, 203, - 131, 232, 73, 23, 149, 86, 174, 59, 193, 92, 121, 76, 154, 211, 44, - 96, 10, 84, 159, 133, 211, 56, 103, 0, 59, 2, 96, 20, 69, 2, 32, - 179, 16, 184, 108, 76, 215, 64, 195, 78, 143, 73, 177, 139, 20, 144, - 98, 231, 41, 117, 255, 220, 115, 41, 59, 27, 75, 56, 10, 0, 0, 0, 0, - 0, 0, 0, 128, 179, 250, 48, 211, 76, 10, 70, 74, 230, 219, 139, 96, - 78, 88, 112, 33, 170, 44, 184, 59, 200, 155, 143, 128, 40, 222, 179, - 210, 190, 84, 16, 182, 21, 34, 94, 28, 193, 163, 226, 51, 251, 134, - 233, 187, 121, 63, 157, 240, 165, 203, 92, 16, 146, 120, 190, 229, - 251, 129, 29, 45, 32, 29, 6 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 136, 220, 52, 23, 213, 5, 142, 196, + 180, 80, 62, 12, 18, 234, 26, 10, 137, 190, 32, 15, 233, 137, 34, 66, 61, 67, 52, 1, + 79, 166, 176, 238, 207, 48, 195, 55, 171, 225, 252, 130, 161, 56, 151, 29, 193, 32, 25, + 157, 249, 39, 80, 193, 214, 96, 167, 147, 25, 130, 45, 42, 64, 208, 182, 164, 10, 0, 0, + 0, 0, 0, 0, 0, 234, 236, 231, 45, 70, 171, 135, 246, 136, 153, 38, 167, 91, 134, 150, + 242, 215, 83, 56, 238, 16, 119, 55, 170, 32, 69, 255, 248, 164, 20, 57, 50, 122, 115, + 135, 96, 80, 203, 131, 232, 73, 23, 149, 86, 174, 59, 193, 92, 121, 76, 154, 211, 44, + 96, 10, 84, 159, 133, 211, 56, 103, 0, 59, 2, 96, 20, 69, 2, 32, 179, 16, 184, 108, 76, + 215, 64, 195, 78, 143, 73, 177, 139, 20, 144, 98, 231, 41, 117, 255, 220, 115, 41, 59, + 27, 75, 56, 10, 0, 0, 0, 0, 0, 0, 0, 128, 179, 250, 48, 211, 76, 10, 70, 74, 230, 219, + 139, 96, 78, 88, 112, 33, 170, 44, 184, 59, 200, 155, 143, 128, 40, 222, 179, 210, 190, + 84, 16, 182, 21, 34, 94, 28, 193, 163, 226, 51, 251, 134, 233, 187, 121, 63, 157, 240, + 165, 203, 92, 16, 146, 120, 190, 229, 251, 129, 29, 45, 32, 29, 6, ]; let equivocation_proof1: sp_consensus_grandpa::EquivocationProof = Decode::decode(&mut &EQUIVOCATION_PROOF_BLOB[..]).unwrap(); let equivocation_proof2 = equivocation_proof1.clone(); - }: { - sp_consensus_grandpa::check_equivocation_proof(equivocation_proof1); - } verify { + + #[block] + { + sp_consensus_grandpa::check_equivocation_proof(equivocation_proof1); + } + assert!(sp_consensus_grandpa::check_equivocation_proof(equivocation_proof2)); } - note_stalled { + #[benchmark] + fn note_stalled() { let delay = 1000u32.into(); let best_finalized_block_number = 1u32.into(); - }: _(RawOrigin::Root, delay, best_finalized_block_number) - verify { + #[extrinsic_call] + _(RawOrigin::Root, delay, best_finalized_block_number); + assert!(Grandpa::::stalled().is_some()); } diff --git a/substrate/frame/grandpa/src/equivocation.rs b/substrate/frame/grandpa/src/equivocation.rs index b213c1ceb721..2366c957e9ab 100644 --- a/substrate/frame/grandpa/src/equivocation.rs +++ b/substrate/frame/grandpa/src/equivocation.rs @@ -110,7 +110,7 @@ impl Offence for EquivocationOffence { /// /// This type implements `OffenceReportSystem` such that: /// - Equivocation reports are published on-chain as unsigned extrinsic via -/// `offchain::SendTransactionTypes`. +/// `offchain::CreateTransactionBase`. /// - On-chain validity checks and processing are mostly delegated to the user provided generic /// types implementing `KeyOwnerProofSystem` and `ReportOffence` traits. /// - Offence reporter for unsigned transactions is fetched via the the authorship pallet. @@ -122,7 +122,7 @@ impl (EquivocationProof>, T::KeyOwnerProof), > for EquivocationReportSystem where - T: Config + pallet_authorship::Config + frame_system::offchain::SendTransactionTypes>, + T: Config + pallet_authorship::Config + frame_system::offchain::CreateInherent>, R: ReportOffence< T::AccountId, P::IdentificationTuple, @@ -144,7 +144,8 @@ where equivocation_proof: Box::new(equivocation_proof), key_owner_proof, }; - let res = SubmitTransaction::>::submit_unsigned_transaction(call.into()); + let xt = T::create_inherent(call.into()); + let res = SubmitTransaction::>::submit_transaction(xt); match res { Ok(_) => info!(target: LOG_TARGET, "Submitted equivocation report"), Err(e) => error!(target: LOG_TARGET, "Error submitting equivocation report: {:?}", e), diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index caac4107cfb7..87369c23948c 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -72,14 +72,23 @@ impl frame_system::Config for Test { type AccountData = pallet_balances::AccountData; } -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = TestXt; } +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + TestXt::new_bare(call) + } +} + parameter_types! { pub const Period: u64 = 1; pub const Offset: u64 = 0; @@ -288,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 8b12d63adaad..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); @@ -882,7 +882,7 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight.any_gt(Weight::zero())); + assert!(info.call_weight.any_gt(Weight::zero())); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. diff --git a/substrate/frame/identity/README.md b/substrate/frame/identity/README.md index 94b2ae0231d7..32b75d159a9b 100644 --- a/substrate/frame/identity/README.md +++ b/substrate/frame/identity/README.md @@ -27,15 +27,24 @@ no state-bloat attack is viable. #### Usernames -The pallet provides functionality for username authorities to issue usernames. When an account -receives a username, they get a default instance of `IdentityInfo`. Usernames also serve as a -reverse lookup from username to account. +The pallet provides functionality for username authorities to issue usernames, which are independent +of the identity information functionality; an account can set: +- an identity without setting a username +- a username without setting an identity +- an identity and a username -Username authorities are given an allocation by governance to prevent state bloat. Usernames -impose no cost or deposit on the user. +The username functionality implemented in this pallet is meant to be a user friendly lookup of +accounts. There are mappings in both directions, "account -> username" and "username -> account". -Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can -only map to a single username, known as the *primary*. +To grant a username, a username authority can either: +- be given an allocation by governance of a specific amount of usernames to issue for free, + without any deposit associated with storage costs; +- put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative + to other deposits in the system). + +Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can only +map to a single username, known as the _primary_. This primary username will be the result of a +lookup in the `UsernameOf` map for any given account. ### Interface @@ -50,7 +59,7 @@ only map to a single username, known as the *primary*. - `accept_username` - Accept a username issued by a username authority. - `remove_expired_approval` - Remove a username that was issued but never accepted. - `set_primary_username` - Set a given username as an account's primary. -- `remove_dangling_username` - Remove a username that maps to an account without an identity. +- `remove_username` - Remove a username after its grace period has ended. ##### For General Users with Sub-Identities - `set_subs` - Set the sub-accounts of an identity. @@ -66,12 +75,14 @@ only map to a single username, known as the *primary*. ##### For Username Authorities - `set_username_for` - Set a username for a given account. The account must approve it. +- `unbind_username` - Start the grace period for a username. ##### For Superusers - `add_registrar` - Add a new registrar to the system. - `kill_identity` - Forcibly remove the associated identity; the deposit is lost. - `add_username_authority` - Add an account with the ability to issue usernames. - `remove_username_authority` - Remove an account with the ability to issue usernames. +- `kill_username` - Forcibly remove a username. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index ab04000c2281..bab581e92540 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use crate::Pallet as Identity; +use crate::{migration::v2::LazyMigrationV1ToV2, Pallet as Identity}; use alloc::{vec, vec::Vec}; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ @@ -593,19 +593,19 @@ mod benchmarks { assert_ok!(Identity::::add_username_authority( origin.clone(), authority_lookup.clone(), - suffix, + suffix.clone(), allocation )); #[extrinsic_call] - _(origin as T::RuntimeOrigin, authority_lookup); + _(origin as T::RuntimeOrigin, suffix.into(), authority_lookup); assert_last_event::(Event::::AuthorityRemoved { authority }.into()); Ok(()) } #[benchmark] - fn set_username_for() -> Result<(), BenchmarkError> { + fn set_username_for(p: Linear<0, 1>) -> Result<(), BenchmarkError> { // Set up a username authority. let auth_origin = T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); @@ -613,6 +613,7 @@ mod benchmarks { let authority_lookup = T::Lookup::unlookup(authority.clone()); let suffix = bench_suffix(); let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); Identity::::add_username_authority( auth_origin, @@ -634,9 +635,20 @@ mod benchmarks { // Verify signature here to avoid surprise errors at runtime assert!(signature.verify(&bounded_username[..], &public.into())); + let use_allocation = match p { + 0 => false, + 1 => true, + _ => unreachable!(), + }; #[extrinsic_call] - _(RawOrigin::Signed(authority.clone()), who_lookup, username, Some(signature.into())); + set_username_for( + RawOrigin::Signed(authority.clone()), + who_lookup, + bounded_username.clone().into(), + Some(signature.into()), + use_allocation, + ); assert_has_event::( Event::::UsernameSet { @@ -648,6 +660,15 @@ mod benchmarks { assert_has_event::( Event::::PrimaryUsernameSet { who: who_account, username: bounded_username }.into(), ); + if use_allocation { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); + } else { + assert_eq!( + T::Currency::free_balance(&authority), + BalanceOf::::max_value() - T::UsernameDeposit::get() + ); + } Ok(()) } @@ -656,7 +677,7 @@ mod benchmarks { let caller: T::AccountId = whitelisted_caller(); let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone()); + Identity::::queue_acceptance(&caller, username.clone(), Provider::Allocation); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), username.clone()); @@ -666,10 +687,35 @@ mod benchmarks { } #[benchmark] - fn remove_expired_approval() -> Result<(), BenchmarkError> { + fn remove_expired_approval(p: Linear<0, 1>) -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + let caller: T::AccountId = whitelisted_caller(); - let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone()); + let username = bounded_username::(bench_username(), suffix.clone()); + let username_deposit = T::UsernameDeposit::get(); + let provider = match p { + 0 => { + let _ = T::Currency::reserve(&authority, username_deposit); + Provider::AuthorityDeposit(username_deposit) + }, + 1 => Provider::Allocation, + _ => unreachable!(), + }; + Identity::::queue_acceptance(&caller, username.clone(), provider); let expected_expiration = frame_system::Pallet::::block_number() + T::PendingUsernameExpiration::get(); @@ -680,6 +726,16 @@ mod benchmarks { _(RawOrigin::Signed(caller.clone()), username); assert_last_event::(Event::::PreapprovalExpired { whose: caller }.into()); + match p { + 0 => { + assert_eq!(T::Currency::free_balance(&authority), BalanceOf::::max_value()); + }, + 1 => { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + }, + _ => unreachable!(), + } Ok(()) } @@ -690,8 +746,8 @@ mod benchmarks { let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username); - Identity::::insert_username(&caller, second_username.clone()); + Identity::::insert_username(&caller, first_username, Provider::Allocation); + Identity::::insert_username(&caller, second_username.clone(), Provider::Allocation); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), second_username.clone()); @@ -703,24 +759,185 @@ mod benchmarks { } #[benchmark] - fn remove_dangling_username() -> Result<(), BenchmarkError> { - let caller: T::AccountId = whitelisted_caller(); - let first_username = bounded_username::(bench_username(), bench_suffix()); - let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); + fn unbind_username() -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); - // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username); - Identity::::insert_username(&caller, second_username.clone()); + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; - // User calls `clear_identity`, leaving their second username as "dangling" - Identity::::clear_identity(RawOrigin::Signed(caller.clone()).into())?; + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + + let username_deposit = T::UsernameDeposit::get(); + Identity::::insert_username( + &caller, + username.clone(), + Provider::AuthorityDeposit(username_deposit), + ); #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), second_username.clone()); + _(RawOrigin::Signed(authority), username.clone()); - assert_last_event::( - Event::::DanglingUsernameRemoved { who: caller, username: second_username }.into(), + assert_last_event::(Event::::UsernameUnbound { username }.into()); + Ok(()) + } + + #[benchmark] + fn remove_username() -> Result<(), BenchmarkError> { + // Set up a username authority. + let authority: T::AccountId = account("authority", 0, SEED); + let suffix = bench_suffix(); + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + + let username_deposit = T::UsernameDeposit::get(); + Identity::::insert_username( + &caller, + username.clone(), + Provider::AuthorityDeposit(username_deposit), ); + let now = frame_system::Pallet::::block_number(); + let expiry = now + T::UsernameGracePeriod::get(); + UnbindingUsernames::::insert(&username, expiry); + + frame_system::Pallet::::set_block_number(expiry); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), username.clone()); + + assert_last_event::(Event::::UsernameRemoved { username }.into()); + Ok(()) + } + + #[benchmark] + fn kill_username(p: Linear<0, 1>) -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + let username_deposit = T::UsernameDeposit::get(); + let provider = match p { + 0 => { + let _ = T::Currency::reserve(&authority, username_deposit); + Provider::AuthorityDeposit(username_deposit) + }, + 1 => Provider::Allocation, + _ => unreachable!(), + }; + Identity::::insert_username(&caller, username.clone(), provider); + UnbindingUsernames::::insert(&username, frame_system::Pallet::::block_number()); + + #[extrinsic_call] + _(RawOrigin::Root, username.clone()); + + assert_last_event::(Event::::UsernameKilled { username }.into()); + match p { + 0 => { + assert_eq!( + T::Currency::free_balance(&authority), + BalanceOf::::max_value() - username_deposit + ); + }, + 1 => { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + }, + _ => unreachable!(), + } + Ok(()) + } + + #[benchmark] + fn migration_v2_authority_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + assert_eq!(AuthorityOf::::iter().count(), 0); + #[block] + { + LazyMigrationV1ToV2::::authority_step(None); + } + assert_eq!(AuthorityOf::::get(&setup.suffix).unwrap().account_id, setup.authority); + Ok(()) + } + + #[benchmark] + fn migration_v2_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + assert_eq!(UsernameInfoOf::::iter().count(), 0); + #[block] + { + LazyMigrationV1ToV2::::username_step(None); + } + assert_eq!(UsernameInfoOf::::iter().next().unwrap().1.owner, setup.account); + Ok(()) + } + + #[benchmark] + fn migration_v2_identity_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + #[block] + { + LazyMigrationV1ToV2::::identity_step(None); + } + assert!(IdentityOf::::get(&setup.account).is_some()); + Ok(()) + } + + #[benchmark] + fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + #[block] + { + LazyMigrationV1ToV2::::pending_username_step(None); + } + assert!(PendingUsernames::::get(&setup.username).is_some()); + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_cleanup(); + #[block] + { + LazyMigrationV1ToV2::::cleanup_authority_step(None); + } + LazyMigrationV1ToV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_cleanup(); + #[block] + { + LazyMigrationV1ToV2::::cleanup_username_step(None); + } + LazyMigrationV1ToV2::::check_username_cleanup_validity(setup.username, setup.account); Ok(()) } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 08e29ddffd12..6a71e831cca1 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -42,15 +42,26 @@ //! //! ### Usernames //! -//! The pallet provides functionality for username authorities to issue usernames. When an account -//! receives a username, they get a default instance of `IdentityInfo`. Usernames also serve as a -//! reverse lookup from username to account. +//! The pallet provides functionality for username authorities to issue usernames, which are +//! independent of the identity information functionality; an account can set: +//! - an identity without setting a username +//! - a username without setting an identity +//! - an identity and a username //! -//! Username authorities are given an allocation by governance to prevent state bloat. Usernames -//! impose no cost or deposit on the user. +//! The username functionality implemented in this pallet is meant to be a user friendly lookup of +//! accounts. There are mappings in both directions, "account -> username" and "username -> +//! account". +//! +//! Usernames are granted by authorities and grouped by suffix, with each suffix being administered +//! by one authority. To grant a username, a username authority can either: +//! - be given an allocation by governance of a specific amount of usernames to issue for free, +//! without any deposit associated with storage costs; +//! - put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative +//! to other deposits in the system) //! //! Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can -//! only map to a single username, known as the _primary_. +//! only map to a single username, known as the _primary_. This primary username will be the result +//! of a lookup in the [UsernameOf] map for any given account. //! //! ## Interface //! @@ -65,7 +76,7 @@ //! * `accept_username` - Accept a username issued by a username authority. //! * `remove_expired_approval` - Remove a username that was issued but never accepted. //! * `set_primary_username` - Set a given username as an account's primary. -//! * `remove_dangling_username` - Remove a username that maps to an account without an identity. +//! * `remove_username` - Remove a username after its grace period has ended. //! //! #### For General Users with Sub-Identities //! * `set_subs` - Set the sub-accounts of an identity. @@ -81,12 +92,14 @@ //! //! #### For Username Authorities //! * `set_username_for` - Set a username for a given account. The account must approve it. +//! * `unbind_username` - Start the grace period for a username. //! //! #### For Superusers //! * `add_registrar` - Add a new registrar to the system. //! * `kill_identity` - Forcibly remove the associated identity; the deposit is lost. //! * `add_username_authority` - Add an account with the ability to issue usernames. //! * `remove_username_authority` - Remove an account with the ability to issue usernames. +//! * `kill_username` - Forcibly remove a username. //! //! [`Call`]: ./enum.Call.html //! [`Config`]: ./trait.Config.html @@ -103,13 +116,15 @@ pub mod weights; extern crate alloc; -use crate::types::{AuthorityPropertiesOf, Suffix, Username}; +use crate::types::{AuthorityProperties, Provider, Suffix, Username, UsernameInformation}; use alloc::{boxed::Box, vec::Vec}; use codec::Encode; use frame_support::{ ensure, pallet_prelude::{DispatchError, DispatchResult}, - traits::{BalanceStatus, Currency, Get, OnUnbalanced, ReservableCurrency, StorageVersion}, + traits::{ + BalanceStatus, Currency, Defensive, Get, OnUnbalanced, ReservableCurrency, StorageVersion, + }, BoundedVec, }; use frame_system::pallet_prelude::*; @@ -128,6 +143,7 @@ type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type ProviderOf = Provider>; #[frame_support::pallet] pub mod pallet { @@ -150,6 +166,11 @@ pub mod pallet { #[pallet::constant] type ByteDeposit: Get>; + /// The amount held on deposit per registered username. This value should change only in + /// runtime upgrades with proper migration of existing deposits. + #[pallet::constant] + type UsernameDeposit: Get>; + /// The amount held on deposit for a registered subaccount. This should account for the fact /// that one storage item's value will increase by the size of an account ID, and there will /// be another trie item whose value is the size of an account ID plus 32 bytes. @@ -192,6 +213,11 @@ pub mod pallet { #[pallet::constant] type PendingUsernameExpiration: Get>; + /// The number of blocks that must pass to enable the permanent deletion of a username by + /// its respective authority. + #[pallet::constant] + type UsernameGracePeriod: Get>; + /// The maximum length of a suffix. #[pallet::constant] type MaxSuffixLength: Get; @@ -204,7 +230,7 @@ pub mod pallet { type WeightInfo: WeightInfo; } - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -219,10 +245,15 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - (Registration, T::MaxRegistrars, T::IdentityInformation>, Option>), + Registration, T::MaxRegistrars, T::IdentityInformation>, OptionQuery, >; + /// Identifies the primary username of an account. + #[pallet::storage] + pub type UsernameOf = + StorageMap<_, Twox64Concat, T::AccountId, Username, OptionQuery>; + /// The super-identity of an alternative "sub" identity together with its name, within that /// context. If the account is not some other account's sub-identity, then just `None`. #[pallet::storage] @@ -265,22 +296,28 @@ pub mod pallet { /// A map of the accounts who are authorized to grant usernames. #[pallet::storage] - pub type UsernameAuthorities = - StorageMap<_, Twox64Concat, T::AccountId, AuthorityPropertiesOf, OptionQuery>; + pub type AuthorityOf = + StorageMap<_, Twox64Concat, Suffix, AuthorityProperties, OptionQuery>; - /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should - /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. + /// Reverse lookup from `username` to the `AccountId` that has registered it and the provider of + /// the username. The `owner` value should be a key in the `UsernameOf` map, but it may not if + /// the user has cleared their username or it has been removed. /// - /// Multiple usernames may map to the same `AccountId`, but `IdentityOf` will only map to one + /// Multiple usernames may map to the same `AccountId`, but `UsernameOf` will only map to one /// primary username. #[pallet::storage] - pub type AccountOfUsername = - StorageMap<_, Blake2_128Concat, Username, T::AccountId, OptionQuery>; + pub type UsernameInfoOf = StorageMap< + _, + Blake2_128Concat, + Username, + UsernameInformation>, + OptionQuery, + >; /// Usernames that an authority has granted, but that the account controller has not confirmed /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call - /// [`Call::accept_username`]. + /// [accept_username](`Call::accept_username`). /// /// First tuple item is the account and second is the acceptance deadline. #[pallet::storage] @@ -288,10 +325,18 @@ pub mod pallet { _, Blake2_128Concat, Username, - (T::AccountId, BlockNumberFor), + (T::AccountId, BlockNumberFor, ProviderOf), OptionQuery, >; + /// Usernames for which the authority that granted them has started the removal process by + /// unbinding them. Each unbinding username maps to its grace period expiry, which is the first + /// block in which the username could be deleted through a + /// [remove_username](`Call::remove_username`) call. + #[pallet::storage] + pub type UnbindingUsernames = + StorageMap<_, Blake2_128Concat, Username, BlockNumberFor, OptionQuery>; + #[pallet::error] pub enum Error { /// Too many subs-accounts. @@ -346,6 +391,15 @@ pub mod pallet { NoUsername, /// The username cannot be forcefully removed because it can still be accepted. NotExpired, + /// The username cannot be removed because it's still in the grace period. + TooEarly, + /// The username cannot be removed because it is not unbinding. + NotUnbinding, + /// The username cannot be unbound because it is already unbinding. + AlreadyUnbinding, + /// The action cannot be performed because of insufficient privileges (e.g. authority + /// trying to unbind a username provided by the system). + InsufficientPrivileges, } #[pallet::event] @@ -367,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 @@ -387,6 +445,12 @@ pub mod pallet { /// A dangling username (as in, a username corresponding to an account that has removed its /// identity) has been removed. DanglingUsernameRemoved { who: T::AccountId, username: Username }, + /// A username has been unbound. + UsernameUnbound { username: Username }, + /// A username has been removed. + UsernameRemoved { username: Username }, + /// A username has been killed. + UsernameKilled { username: Username }, } #[pallet::call] @@ -444,24 +508,18 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let (mut id, username) = match IdentityOf::::get(&sender) { - Some((mut id, maybe_username)) => ( - { - // Only keep non-positive judgements. - id.judgements.retain(|j| j.1.is_sticky()); - id.info = *info; - id - }, - maybe_username, - ), - None => ( - Registration { - info: *info, - judgements: BoundedVec::default(), - deposit: Zero::zero(), - }, - None, - ), + let mut id = match IdentityOf::::get(&sender) { + Some(mut id) => { + // Only keep non-positive judgements. + id.judgements.retain(|j| j.1.is_sticky()); + id.info = *info; + id + }, + None => Registration { + info: *info, + judgements: BoundedVec::default(), + deposit: Zero::zero(), + }, }; let new_deposit = Self::calculate_identity_deposit(&id.info); @@ -470,7 +528,7 @@ pub mod pallet { id.deposit = new_deposit; let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::IdentitySet { who: sender }); Ok(Some(T::WeightInfo::set_identity(judgements as u32)).into()) @@ -537,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 @@ -562,15 +626,11 @@ pub mod pallet { let sender = ensure_signed(origin)?; let (subs_deposit, sub_ids) = SubsOf::::take(&sender); - let (id, maybe_username) = - IdentityOf::::take(&sender).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&sender).ok_or(Error::::NoIdentity)?; let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { SuperOf::::remove(sub); } - if let Some(username) = maybe_username { - AccountOfUsername::::remove(username); - } let err_amount = T::Currency::unreserve(&sender, deposit); debug_assert!(err_amount.is_zero()); @@ -615,7 +675,7 @@ pub mod pallet { .and_then(Option::as_ref) .ok_or(Error::::EmptyIndex)?; ensure!(max_fee >= registrar.fee, Error::::FeeChanged); - let (mut id, username) = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; + let mut id = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; let item = (reg_index, Judgement::FeePaid(registrar.fee)); match id.judgements.binary_search_by_key(®_index, |x| x.0) { @@ -632,7 +692,7 @@ pub mod pallet { T::Currency::reserve(&sender, registrar.fee)?; let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::JudgementRequested { who: sender, @@ -659,7 +719,7 @@ pub mod pallet { reg_index: RegistrarIndex, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let (mut id, username) = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; + let mut id = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; let pos = id .judgements @@ -674,7 +734,7 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, fee); debug_assert!(err_amount.is_zero()); let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::JudgementUnrequested { who: sender, @@ -813,8 +873,7 @@ pub mod pallet { .and_then(Option::as_ref) .filter(|r| r.account == sender) .ok_or(Error::::InvalidIndex)?; - let (mut id, username) = - IdentityOf::::get(&target).ok_or(Error::::InvalidTarget)?; + let mut id = IdentityOf::::get(&target).ok_or(Error::::InvalidTarget)?; if T::Hashing::hash_of(&id.info) != identity { return Err(Error::::JudgementForDifferentIdentity.into()) @@ -841,7 +900,7 @@ pub mod pallet { } let judgements = id.judgements.len(); - IdentityOf::::insert(&target, (id, username)); + IdentityOf::::insert(&target, id); Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index }); Ok(Some(T::WeightInfo::provide_judgement(judgements as u32)).into()) @@ -874,15 +933,11 @@ pub mod pallet { let target = T::Lookup::lookup(target)?; // Grab their deposit (and check that they have one). let (subs_deposit, sub_ids) = SubsOf::::take(&target); - let (id, maybe_username) = - IdentityOf::::take(&target).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&target).ok_or(Error::::NoIdentity)?; let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { SuperOf::::remove(sub); } - if let Some(username) = maybe_username { - AccountOfUsername::::remove(username); - } // Slash their deposit from them. T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0); @@ -947,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(()) } @@ -1010,8 +1067,9 @@ pub mod pallet { /// Add an `AccountId` with permission to grant usernames with a given `suffix` appended. /// - /// The authority can grant up to `allocation` usernames. To top up their allocation, they - /// should just issue (or request via governance) a new `add_username_authority` call. + /// The authority can grant up to `allocation` usernames. To top up the allocation or + /// change the account used to grant usernames, this call can be used with the updated + /// parameters to overwrite the existing configuration. #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::add_username_authority())] pub fn add_username_authority( @@ -1024,13 +1082,12 @@ pub mod pallet { let authority = T::Lookup::lookup(authority)?; // We don't need to check the length because it gets checked when casting into a // `BoundedVec`. - Self::validate_username(&suffix, None).map_err(|_| Error::::InvalidSuffix)?; + Self::validate_suffix(&suffix)?; let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; - // The authority may already exist, but we don't need to check. They might be changing - // their suffix or adding allocation, so we just want to overwrite whatever was there. - UsernameAuthorities::::insert( - &authority, - AuthorityPropertiesOf:: { suffix, allocation }, + // The call is `UsernameAuthorityOrigin` guarded, overwrite the old entry if it exists. + AuthorityOf::::insert( + &suffix, + AuthorityProperties:: { account_id: authority.clone(), allocation }, ); Self::deposit_event(Event::AuthorityAdded { authority }); Ok(()) @@ -1041,18 +1098,26 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_username_authority())] pub fn remove_username_authority( origin: OriginFor, + suffix: Vec, authority: AccountIdLookupOf, ) -> DispatchResult { T::UsernameAuthorityOrigin::ensure_origin(origin)?; + let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; let authority = T::Lookup::lookup(authority)?; - UsernameAuthorities::::take(&authority).ok_or(Error::::NotUsernameAuthority)?; + let properties = + AuthorityOf::::take(&suffix).ok_or(Error::::NotUsernameAuthority)?; + ensure!(properties.account_id == authority, Error::::InvalidSuffix); Self::deposit_event(Event::AuthorityRemoved { authority }); Ok(()) } /// Set the username for `who`. Must be called by a username authority. /// - /// The authority must have an `allocation`. Users can either pre-sign their usernames or + /// If `use_allocation` is set, the authority must have a username allocation available to + /// spend. Otherwise, the authority will need to put up a deposit for registering the + /// username. + /// + /// Users can either pre-sign their usernames or /// accept them later. /// /// Usernames must: @@ -1060,45 +1125,42 @@ pub mod pallet { /// - When combined with the suffix of the issuing authority be _less than_ the /// `MaxUsernameLength`. #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::set_username_for())] + #[pallet::weight(T::WeightInfo::set_username_for(if *use_allocation { 1 } else { 0 }))] pub fn set_username_for( origin: OriginFor, who: AccountIdLookupOf, username: Vec, signature: Option, + use_allocation: bool, ) -> DispatchResult { // Ensure origin is a Username Authority and has an allocation. Decrement their // allocation by one. let sender = ensure_signed(origin)?; - let suffix = UsernameAuthorities::::try_mutate( - &sender, - |maybe_authority| -> Result, DispatchError> { + let suffix = Self::validate_username(&username)?; + let provider = AuthorityOf::::try_mutate( + &suffix, + |maybe_authority| -> Result, DispatchError> { let properties = maybe_authority.as_mut().ok_or(Error::::NotUsernameAuthority)?; - ensure!(properties.allocation > 0, Error::::NoAllocation); - properties.allocation.saturating_dec(); - Ok(properties.suffix.clone()) + ensure!(properties.account_id == sender, Error::::NotUsernameAuthority); + if use_allocation { + ensure!(properties.allocation > 0, Error::::NoAllocation); + properties.allocation.saturating_dec(); + Ok(Provider::new_with_allocation()) + } else { + let deposit = T::UsernameDeposit::get(); + T::Currency::reserve(&sender, deposit)?; + Ok(Provider::new_with_deposit(deposit)) + } }, )?; - // Ensure that the username only contains allowed characters. We already know the suffix - // does. - let username_length = username.len().saturating_add(suffix.len()) as u32; - Self::validate_username(&username, Some(username_length))?; - - // Concatenate the username with suffix and cast into a BoundedVec. Should be infallible - // since we already ensured it is below the max length. - let mut full_username = - Vec::with_capacity(username.len().saturating_add(suffix.len()).saturating_add(1)); - full_username.extend(username); - full_username.extend(b"."); - full_username.extend(suffix); let bounded_username = - Username::::try_from(full_username).map_err(|_| Error::::InvalidUsername)?; + Username::::try_from(username).map_err(|_| Error::::InvalidUsername)?; // Usernames must be unique. Ensure it's not taken. ensure!( - !AccountOfUsername::::contains_key(&bounded_username), + !UsernameInfoOf::::contains_key(&bounded_username), Error::::UsernameTaken ); ensure!( @@ -1112,10 +1174,10 @@ pub mod pallet { // Account has pre-signed an authorization. Verify the signature provided and grant // the username directly. Self::validate_signature(&bounded_username[..], &s, &who)?; - Self::insert_username(&who, bounded_username); + Self::insert_username(&who, bounded_username, provider); } else { // The user must accept the username, therefore, queue it. - Self::queue_acceptance(&who, bounded_username); + Self::queue_acceptance(&who, bounded_username, provider); } Ok(()) } @@ -1129,10 +1191,10 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let (approved_for, _) = + let (approved_for, _, provider) = PendingUsernames::::take(&username).ok_or(Error::::NoUsername)?; ensure!(approved_for == who.clone(), Error::::InvalidUsername); - Self::insert_username(&who, username.clone()); + Self::insert_username(&who, username.clone(), provider); Self::deposit_event(Event::UsernameSet { who: who.clone(), username }); Ok(Pays::No.into()) } @@ -1141,17 +1203,37 @@ pub mod pallet { /// accepted by the user and must now be beyond its expiration. The call must include the /// full username, as in `username.suffix`. #[pallet::call_index(19)] - #[pallet::weight(T::WeightInfo::remove_expired_approval())] + #[pallet::weight(T::WeightInfo::remove_expired_approval(0))] pub fn remove_expired_approval( origin: OriginFor, username: Username, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - if let Some((who, expiration)) = PendingUsernames::::take(&username) { + if let Some((who, expiration, provider)) = PendingUsernames::::take(&username) { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); + let actual_weight = match provider { + Provider::AuthorityDeposit(deposit) => { + let suffix = Self::suffix_of_username(&username) + .ok_or(Error::::InvalidUsername)?; + let authority_account = AuthorityOf::::get(&suffix) + .map(|auth_info| auth_info.account_id) + .ok_or(Error::::NotUsernameAuthority)?; + let err_amount = T::Currency::unreserve(&authority_account, deposit); + debug_assert!(err_amount.is_zero()); + T::WeightInfo::remove_expired_approval(0) + }, + Provider::Allocation => { + // We don't refund the allocation, it is lost, but we refund some weight. + T::WeightInfo::remove_expired_approval(1) + }, + Provider::System => { + // Usernames added by the system shouldn't ever be expired. + return Err(Error::::InvalidTarget.into()); + }, + }; Self::deposit_event(Event::PreapprovalExpired { whose: who.clone() }); - Ok(Pays::No.into()) + Ok((Some(actual_weight), Pays::No).into()) } else { Err(Error::::NoUsername.into()) } @@ -1164,107 +1246,139 @@ pub mod pallet { // ensure `username` maps to `origin` (i.e. has already been set by an authority). let who = ensure_signed(origin)?; let account_of_username = - AccountOfUsername::::get(&username).ok_or(Error::::NoUsername)?; + UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?.owner; ensure!(who == account_of_username, Error::::InvalidUsername); - let (registration, _maybe_username) = - IdentityOf::::get(&who).ok_or(Error::::NoIdentity)?; - IdentityOf::::insert(&who, (registration, Some(username.clone()))); + UsernameOf::::insert(&who, username.clone()); Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); Ok(()) } - /// Remove a username that corresponds to an account with no identity. Exists when a user - /// gets a username but then calls `clear_identity`. + /// Start the process of removing a username by placing it in the unbinding usernames map. + /// Once the grace period has passed, the username can be deleted by calling + /// [remove_username](crate::Call::remove_username). #[pallet::call_index(21)] - #[pallet::weight(T::WeightInfo::remove_dangling_username())] - pub fn remove_dangling_username( + #[pallet::weight(T::WeightInfo::unbind_username())] + pub fn unbind_username(origin: OriginFor, username: Username) -> DispatchResult { + let who = ensure_signed(origin)?; + let username_info = + UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?; + let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + let authority_account = AuthorityOf::::get(&suffix) + .map(|auth_info| auth_info.account_id) + .ok_or(Error::::NotUsernameAuthority)?; + ensure!(who == authority_account, Error::::NotUsernameAuthority); + match username_info.provider { + Provider::AuthorityDeposit(_) | Provider::Allocation => { + let now = frame_system::Pallet::::block_number(); + let grace_period_expiry = now.saturating_add(T::UsernameGracePeriod::get()); + UnbindingUsernames::::try_mutate(&username, |maybe_init| { + if maybe_init.is_some() { + return Err(Error::::AlreadyUnbinding); + } + *maybe_init = Some(grace_period_expiry); + Ok(()) + })?; + }, + Provider::System => return Err(Error::::InsufficientPrivileges.into()), + } + Self::deposit_event(Event::UsernameUnbound { username }); + Ok(()) + } + + /// Permanently delete a username which has been unbinding for longer than the grace period. + /// Caller is refunded the fee if the username expired and the removal was successful. + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::remove_username())] + pub fn remove_username( origin: OriginFor, username: Username, ) -> DispatchResultWithPostInfo { - // ensure `username` maps to `origin` (i.e. has already been set by an authority). let _ = ensure_signed(origin)?; - let who = AccountOfUsername::::take(&username).ok_or(Error::::NoUsername)?; - ensure!(!IdentityOf::::contains_key(&who), Error::::InvalidUsername); - Self::deposit_event(Event::DanglingUsernameRemoved { who: who.clone(), username }); + let grace_period_expiry = + UnbindingUsernames::::take(&username).ok_or(Error::::NotUnbinding)?; + let now = frame_system::Pallet::::block_number(); + ensure!(now >= grace_period_expiry, Error::::TooEarly); + let username_info = UsernameInfoOf::::take(&username) + .defensive_proof("an unbinding username must exist") + .ok_or(Error::::NoUsername)?; + // If this is the primary username, remove the entry from the account -> username map. + UsernameOf::::mutate(&username_info.owner, |maybe_primary| { + if maybe_primary.as_ref().map_or(false, |primary| *primary == username) { + *maybe_primary = None; + } + }); + match username_info.provider { + Provider::AuthorityDeposit(username_deposit) => { + let suffix = Self::suffix_of_username(&username) + .defensive_proof("registered username must be valid") + .ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) + { + let err_amount = + T::Currency::unreserve(&authority_account, username_deposit); + debug_assert!(err_amount.is_zero()); + } + }, + Provider::Allocation => { + // We don't refund the allocation, it is lost. + }, + Provider::System => return Err(Error::::InsufficientPrivileges.into()), + } + Self::deposit_event(Event::UsernameRemoved { username }); Ok(Pays::No.into()) } + + /// Call with [ForceOrigin](crate::Config::ForceOrigin) privileges which deletes a username + /// and slashes any deposit associated with it. + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::kill_username(0))] + pub fn kill_username( + origin: OriginFor, + username: Username, + ) -> DispatchResultWithPostInfo { + T::ForceOrigin::ensure_origin(origin)?; + let username_info = + UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + // If this is the primary username, remove the entry from the account -> username map. + UsernameOf::::mutate(&username_info.owner, |maybe_primary| { + if match maybe_primary { + Some(primary) if *primary == username => true, + _ => false, + } { + *maybe_primary = None; + } + }); + let _ = UnbindingUsernames::::take(&username); + let actual_weight = match username_info.provider { + Provider::AuthorityDeposit(username_deposit) => { + let suffix = + Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) + { + T::Slashed::on_unbalanced( + T::Currency::slash_reserved(&authority_account, username_deposit).0, + ); + } + T::WeightInfo::kill_username(0) + }, + Provider::Allocation => { + // We don't refund the allocation, it is lost, but we do refund some weight. + T::WeightInfo::kill_username(1) + }, + Provider::System => { + // Force origin can remove system usernames. + T::WeightInfo::kill_username(1) + }, + }; + Self::deposit_event(Event::UsernameKilled { username }); + Ok((Some(actual_weight), Pays::No).into()) + } } } impl Pallet { - /// Information that is pertinent to identify the entity behind an account. First item is the - /// registration, second is the account's primary username. - /// - /// TWOX-NOTE: OK ― `AccountId` is a secure hash. - pub fn identity( - who: T::AccountId, - ) -> Option<( - Registration, T::MaxRegistrars, T::IdentityInformation>, - Option>, - )> { - IdentityOf::::get(who) - } - - /// The super-identity of an alternative "sub" identity together with its name, within that - /// context. If the account is not some other account's sub-identity, then just `None`. - pub fn super_of(who: T::AccountId) -> Option<(T::AccountId, Data)> { - SuperOf::::get(who) - } - - /// Alternative "sub" identities of this account. - /// - /// The first item is the deposit, the second is a vector of the accounts. - /// - /// TWOX-NOTE: OK ― `AccountId` is a secure hash. - pub fn subs_of( - who: T::AccountId, - ) -> (BalanceOf, BoundedVec) { - SubsOf::::get(who) - } - - /// The set of registrars. Not expected to get very big as can only be added through a - /// special origin (likely a council motion). - /// - /// The index into this can be cast to `RegistrarIndex` to get a valid value. - pub fn registrars() -> BoundedVec< - Option< - RegistrarInfo< - BalanceOf, - T::AccountId, - ::FieldsIdentifier, - >, - >, - T::MaxRegistrars, - > { - Registrars::::get() - } - - /// A map of the accounts who are authorized to grant usernames. - pub fn authority(who: T::AccountId) -> Option> { - UsernameAuthorities::::get(who) - } - - /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should - /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. - /// - /// Multiple usernames may map to the same `AccountId`, but `IdentityOf` will only map to one - /// primary username. - pub fn username(username: Username) -> Option { - AccountOfUsername::::get(username) - } - - /// Usernames that an authority has granted, but that the account controller has not confirmed - /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature - /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call - /// [`Call::accept_username`]. - /// - /// First tuple item is the account and second is the acceptance deadline. - pub fn preapproved_usernames( - username: Username, - ) -> Option<(T::AccountId, BlockNumberFor)> { - PendingUsernames::::get(username) - } - /// Get the subs of an account. pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> { SubsOf::::get(who) @@ -1300,7 +1414,7 @@ impl Pallet { fields: ::FieldsIdentifier, ) -> bool { IdentityOf::::get(who) - .map_or(false, |(registration, _username)| (registration.info.has_identity(fields))) + .map_or(false, |registration| (registration.info.has_identity(fields))) } /// Calculate the deposit required for an identity. @@ -1312,23 +1426,56 @@ impl Pallet { /// Validate that a username conforms to allowed characters/format. /// - /// The function will validate the characters in `username` and that `length` (if `Some`) - /// conforms to the limit. It is not expected to pass a fully formatted username here (i.e. one - /// with any protocol-added characters included, such as a `.`). The suffix is also separately - /// validated by this function to ensure the full username conforms. - fn validate_username(username: &Vec, length: Option) -> DispatchResult { - // Verify input length before allocating a Vec with the user's input. `<` instead of `<=` - // because it needs one element for the point (`username` + `.` + `suffix`). - if let Some(l) = length { - ensure!(l < T::MaxUsernameLength::get(), Error::::InvalidUsername); - } + /// The function will validate the characters in `username`. It is expected to pass a fully + /// formatted username here (i.e. "username.suffix"). The suffix is also separately validated + /// and returned by this function. + fn validate_username(username: &Vec) -> Result, DispatchError> { + // Verify input length before allocating a Vec with the user's input. + ensure!( + username.len() <= T::MaxUsernameLength::get() as usize, + Error::::InvalidUsername + ); + // Usernames cannot be empty. ensure!(!username.is_empty(), Error::::InvalidUsername); + let separator_idx = + username.iter().rposition(|c| *c == b'.').ok_or(Error::::InvalidUsername)?; + ensure!(separator_idx > 0, Error::::InvalidUsername); + let suffix_start = separator_idx.checked_add(1).ok_or(Error::::InvalidUsername)?; + ensure!(suffix_start < username.len(), Error::::InvalidUsername); // Username must be lowercase and alphanumeric. ensure!( - username.iter().all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), + username + .iter() + .take(separator_idx) + .all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), Error::::InvalidUsername ); + let suffix: Suffix = (&username[suffix_start..]) + .to_vec() + .try_into() + .map_err(|_| Error::::InvalidUsername)?; + Ok(suffix) + } + + /// Return the suffix of a username, if it is valid. + fn suffix_of_username(username: &Username) -> Option> { + let separator_idx = username.iter().rposition(|c| *c == b'.')?; + let suffix_start = separator_idx.checked_add(1)?; + if suffix_start >= username.len() { + return None; + } + (&username[suffix_start..]).to_vec().try_into().ok() + } + + /// Validate that a suffix conforms to allowed characters/format. + fn validate_suffix(suffix: &Vec) -> Result<(), DispatchError> { + ensure!(suffix.len() <= T::MaxSuffixLength::get() as usize, Error::::InvalidSuffix); + ensure!(!suffix.is_empty(), Error::::InvalidSuffix); + ensure!( + suffix.iter().all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), + Error::::InvalidSuffix + ); Ok(()) } @@ -1357,34 +1504,22 @@ impl Pallet { } /// A username has met all conditions. Insert the relevant storage items. - pub fn insert_username(who: &T::AccountId, username: Username) { + pub fn insert_username(who: &T::AccountId, username: Username, provider: ProviderOf) { // Check if they already have a primary. If so, leave it. If not, set it. // Likewise, check if they have an identity. If not, give them a minimal one. - let (reg, primary_username, new_is_primary) = match IdentityOf::::get(&who) { + let (primary_username, new_is_primary) = match UsernameOf::::get(&who) { // User has an existing Identity and a primary username. Leave it. - Some((reg, Some(primary))) => (reg, primary, false), + Some(primary) => (primary, false), // User has an Identity but no primary. Set the new one as primary. - Some((reg, None)) => (reg, username.clone(), true), - // User does not have an existing Identity. Give them a fresh default one and set - // their username as primary. - None => ( - Registration { - info: Default::default(), - judgements: Default::default(), - deposit: Zero::zero(), - }, - username.clone(), - true, - ), + None => (username.clone(), true), }; - // Enter in identity map. Note: In the case that the user did not have a pre-existing - // Identity, we have given them the storage item for free. If they ever call - // `set_identity` with identity info, then they will need to place the normal identity - // deposit. - IdentityOf::::insert(&who, (reg, Some(primary_username))); + if new_is_primary { + UsernameOf::::insert(&who, primary_username); + } + let username_info = UsernameInformation { owner: who.clone(), provider }; // Enter in username map. - AccountOfUsername::::insert(username.clone(), &who); + UsernameInfoOf::::insert(username.clone(), username_info); Self::deposit_event(Event::UsernameSet { who: who.clone(), username: username.clone() }); if new_is_primary { Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); @@ -1393,10 +1528,10 @@ impl Pallet { /// A username was granted by an authority, but must be accepted by `who`. Put the username /// into a queue for acceptance. - pub fn queue_acceptance(who: &T::AccountId, username: Username) { + pub fn queue_acceptance(who: &T::AccountId, username: Username, provider: ProviderOf) { let now = frame_system::Pallet::::block_number(); let expiration = now.saturating_add(T::PendingUsernameExpiration::get()); - PendingUsernames::::insert(&username, (who.clone(), expiration)); + PendingUsernames::::insert(&username, (who.clone(), expiration, provider)); Self::deposit_event(Event::UsernameQueued { who: who.clone(), username, expiration }); } @@ -1415,7 +1550,7 @@ impl Pallet { pub fn reap_identity(who: &T::AccountId) -> Result<(u32, u32, u32), DispatchError> { // `take` any storage items keyed by `target` // identity - let (id, _maybe_username) = IdentityOf::::take(&who).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&who).ok_or(Error::::NoIdentity)?; let registrars = id.judgements.len() as u32; let encoded_byte_size = id.info.encoded_size() as u32; @@ -1449,7 +1584,7 @@ impl Pallet { let new_id_deposit = IdentityOf::::try_mutate( &target, |identity_of| -> Result, DispatchError> { - let (reg, _) = identity_of.as_mut().ok_or(Error::::NoIdentity)?; + let reg = identity_of.as_mut().ok_or(Error::::NoIdentity)?; // Calculate what deposit should be let encoded_byte_size = reg.info.encoded_size() as u32; let byte_deposit = @@ -1491,14 +1626,11 @@ impl Pallet { ) -> DispatchResult { IdentityOf::::insert( &who, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: info.clone(), + }, ); Ok(()) } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 8725bfd39df1..3a78692cfcd7 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -15,16 +15,23 @@ //! Storage migrations for the Identity pallet. +extern crate alloc; + use super::*; use frame_support::{ - migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade, + migrations::VersionedMigration, pallet_prelude::*, storage_alias, + traits::UncheckedOnRuntimeUpgrade, IterableStorageMap, }; +#[cfg(feature = "try-runtime")] +use alloc::collections::BTreeMap; #[cfg(feature = "try-runtime")] use codec::{Decode, Encode}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; +pub const PALLET_MIGRATIONS_ID: &[u8; 15] = b"pallet-identity"; + pub mod versioned { use super::*; @@ -37,31 +44,78 @@ pub mod versioned { >; } -pub mod v1 { +/// The old identity types in v0. +mod types_v0 { use super::*; - /// The log target. - const TARGET: &'static str = "runtime::identity::migration::v1"; + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + OptionQuery, + >; +} - /// The old identity type, useful in pre-upgrade. - mod v0 { - use super::*; - use frame_support::storage_alias; +/// The old identity types in v1. +mod types_v1 { + use super::*; - #[storage_alias] - pub type IdentityOf = StorageMap< - Pallet, - Twox64Concat, - ::AccountId, + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ( Registration< BalanceOf, ::MaxRegistrars, ::IdentityInformation, >, - OptionQuery, - >; - } + Option>, + ), + OptionQuery, + >; + + #[storage_alias] + pub type UsernameAuthorities = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + AuthorityProperties>, + OptionQuery, + >; + + #[storage_alias] + pub type AccountOfUsername = StorageMap< + Pallet, + Blake2_128Concat, + Username, + ::AccountId, + OptionQuery, + >; + + #[cfg(feature = "try-runtime")] + #[storage_alias] + pub type PendingUsernames = StorageMap< + Pallet, + Blake2_128Concat, + Username, + (::AccountId, BlockNumberFor), + OptionQuery, + >; +} +pub mod v1 { + use super::*; + + /// The log target. + const TARGET: &'static str = "runtime::identity::migration::v1"; /// Migration to add usernames to Identity info. /// /// `T` is the runtime and `KL` is the key limit to migrate. This is just a safety guard to @@ -71,7 +125,7 @@ pub mod v1 { impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let identities = v0::IdentityOf::::iter().count(); + let identities = types_v0::IdentityOf::::iter().count(); log::info!( target: TARGET, "pre-upgrade state contains '{}' identities.", @@ -91,8 +145,8 @@ pub mod v1 { let mut translated: u64 = 0; let mut interrupted = false; - for (account, registration) in v0::IdentityOf::::iter() { - IdentityOf::::insert(account, (registration, None::>)); + for (account, registration) in types_v0::IdentityOf::::iter() { + types_v1::IdentityOf::::insert(account, (registration, None::>)); translated.saturating_inc(); if translated >= KL { log::warn!( @@ -116,7 +170,7 @@ pub mod v1 { fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { let identities_to_migrate: u64 = Decode::decode(&mut &state[..]) .expect("failed to decode the state from pre-upgrade."); - let identities = IdentityOf::::iter().count() as u64; + let identities = types_v1::IdentityOf::::iter().count() as u64; log::info!("post-upgrade expects '{}' identities to have been migrated.", identities); ensure!(identities_to_migrate == identities, "must migrate all identities."); log::info!(target: TARGET, "migrated all identities."); @@ -124,3 +178,673 @@ pub mod v1 { } } } + +pub mod v2 { + use super::*; + use frame_support::{ + migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, + weights::WeightMeter, + }; + + type HashedKey = BoundedVec>; + // The resulting state of the step and the actual weight consumed. + type StepResultOf = + MigrationState<::AccountId, Username, Suffix>; + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) type BenchmarkingSetupOf = + BenchmarkingSetup, ::AccountId, Username>; + + /// Progressive states of a migration. The migration starts with the first variant and ends with + /// the last. + #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] + pub enum MigrationState { + Authority(A), + FinishedAuthorities, + Identity(HashedKey), + FinishedIdentities, + Username(U), + FinishedUsernames, + PendingUsername(HashedKey), + FinishedPendingUsernames, + CleanupAuthorities(S), + FinishedCleanupAuthorities, + CleanupUsernames(U), + Finished, + } + + #[cfg(feature = "try-runtime")] + #[derive(Encode, Decode)] + struct TryRuntimeState { + authorities: BTreeMap, (T::AccountId, u32)>, + identities: BTreeMap< + T::AccountId, + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + >, + primary_usernames: BTreeMap>, + usernames: BTreeMap, T::AccountId>, + pending_usernames: BTreeMap, (T::AccountId, BlockNumberFor)>, + } + + pub struct LazyMigrationV1ToV2(PhantomData); + impl SteppedMigration for LazyMigrationV1ToV2 { + type Cursor = MigrationState, Suffix>; + type Identifier = MigrationId<15>; + + fn id() -> Self::Identifier { + MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 1, version_to: 2 } + } + + fn step( + mut cursor: Option, + meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + if Pallet::::on_chain_storage_version() != Self::id().version_from as u16 { + return Ok(None); + } + + // Check that we have enough weight for at least the next step. If we don't, then the + // migration cannot be complete. + let required = match &cursor { + Some(state) => Self::required_weight(&state), + // Worst case weight for `authority_step`. + None => T::WeightInfo::migration_v2_authority_step(), + }; + if meter.remaining().any_lt(required) { + return Err(SteppedMigrationError::InsufficientWeight { required }); + } + + loop { + // Check that we would have enough weight to perform this step in the worst case + // scenario. + let required_weight = match &cursor { + Some(state) => Self::required_weight(&state), + // Worst case weight for `authority_step`. + None => T::WeightInfo::migration_v2_authority_step(), + }; + if !meter.can_consume(required_weight) { + break; + } + + let next = match &cursor { + // At first, migrate any authorities. + None => Self::authority_step(None), + // Migrate any remaining authorities. + Some(MigrationState::Authority(maybe_last_authority)) => + Self::authority_step(Some(maybe_last_authority)), + // After the last authority was migrated, start migrating usernames from + // the former `AccountOfUsername` into `UsernameInfoOf`. + Some(MigrationState::FinishedAuthorities) => Self::username_step(None), + // Keep migrating usernames. + Some(MigrationState::Username(maybe_last_username)) => + Self::username_step(Some(maybe_last_username)), + // After the last username was migrated, start migrating all identities in + // `IdentityOf`, which currently hold the primary username of the owner account + // as well as any associated identity. Accounts which set a username but not an + // identity also have a zero deposit identity stored, which will be removed. + Some(MigrationState::FinishedUsernames) => Self::identity_step(None), + // Keep migrating identities. + Some(MigrationState::Identity(last_key)) => + Self::identity_step(Some(last_key.clone())), + // After the last identity was migrated, start migrating usernames pending + // approval from `PendingUsernames`. + Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None), + // Keep migrating pending usernames. + Some(MigrationState::PendingUsername(last_key)) => + Self::pending_username_step(Some(last_key.clone())), + // After the last pending username was migrated, start clearing the storage + // previously associated with authorities in `UsernameAuthority`. + Some(MigrationState::FinishedPendingUsernames) => + Self::cleanup_authority_step(None), + // Keep clearing the obsolete authority storage. + Some(MigrationState::CleanupAuthorities(maybe_last_username)) => + Self::cleanup_authority_step(Some(maybe_last_username)), + // After the last obsolete authority was cleared from storage, start clearing + // the storage previously associated with usernames in `AccountOfUsername`. + Some(MigrationState::FinishedCleanupAuthorities) => + Self::cleanup_username_step(None), + // Keep clearing the obsolete username storage. + Some(MigrationState::CleanupUsernames(maybe_last_username)) => + Self::cleanup_username_step(Some(maybe_last_username)), + // After the last obsolete username was cleared from storage, the migration is + // done. + Some(MigrationState::Finished) => { + StorageVersion::new(Self::id().version_to as u16).put::>(); + return Ok(None) + }, + }; + + cursor = Some(next); + meter.consume(required_weight); + } + + Ok(cursor) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let authorities: BTreeMap, (T::AccountId, u32)> = + types_v1::UsernameAuthorities::::iter() + .map(|(account, authority_properties)| { + ( + authority_properties.account_id, + (account, authority_properties.allocation), + ) + }) + .collect(); + let mut primary_usernames: BTreeMap<_, _> = Default::default(); + let identities = types_v1::IdentityOf::::iter() + .map(|(account, (identity, maybe_username))| { + if let Some(username) = maybe_username { + primary_usernames.insert(account.clone(), username); + } + (account, identity) + }) + .collect::>(); + let usernames = types_v1::AccountOfUsername::::iter().collect::>(); + let pending_usernames: BTreeMap, (T::AccountId, BlockNumberFor)> = + types_v1::PendingUsernames::::iter().collect(); + let state: TryRuntimeState = TryRuntimeState { + authorities, + identities, + primary_usernames, + usernames, + pending_usernames, + }; + + Ok(state.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let mut prev_state: TryRuntimeState = TryRuntimeState::::decode(&mut &state[..]) + .expect("Failed to decode the previous storage state"); + + for (suffix, authority_properties) in AuthorityOf::::iter() { + let (prev_account, prev_allocation) = prev_state + .authorities + .remove(&suffix) + .expect("should have authority in previous state"); + assert_eq!(prev_account, authority_properties.account_id); + assert_eq!(prev_allocation, authority_properties.allocation); + } + assert!(prev_state.authorities.is_empty()); + + for (account, identity) in IdentityOf::::iter() { + assert!(identity.deposit > 0u32.into()); + let prev_identity = prev_state + .identities + .remove(&account) + .expect("should have identity in previous state"); + assert_eq!(identity, prev_identity); + } + + for (account, free_identity) in prev_state.identities.iter() { + assert_eq!(free_identity.deposit, 0u32.into()); + assert!(UsernameOf::::contains_key(&account)); + } + prev_state.identities.clear(); + + for (account, primary_username) in UsernameOf::::iter() { + let prev_primary_username = prev_state + .primary_usernames + .remove(&account) + .expect("should have primary username in previous state"); + assert_eq!(prev_primary_username, primary_username); + } + + for (username, username_info) in UsernameInfoOf::::iter() { + let prev_account = prev_state + .usernames + .remove(&username) + .expect("should have username info in previous state"); + assert_eq!(prev_account, username_info.owner); + assert_eq!(username_info.provider, Provider::Allocation); + } + assert!(prev_state.usernames.is_empty()); + + for (username, (account, expiration, provider)) in PendingUsernames::::iter() { + let (prev_account, prev_expiration) = prev_state + .pending_usernames + .remove(&username) + .expect("should have pending username in previous state"); + assert_eq!(prev_account, account); + assert_eq!(prev_expiration, expiration); + assert_eq!(provider, Provider::Allocation); + } + assert!(prev_state.pending_usernames.is_empty()); + + Ok(()) + } + } + + impl LazyMigrationV1ToV2 { + pub(crate) fn required_weight( + step: &MigrationState, Suffix>, + ) -> Weight { + match step { + MigrationState::Authority(_) => T::WeightInfo::migration_v2_authority_step(), + MigrationState::FinishedAuthorities | MigrationState::Username(_) => + T::WeightInfo::migration_v2_username_step(), + MigrationState::FinishedUsernames | MigrationState::Identity(_) => + T::WeightInfo::migration_v2_identity_step(), + MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) => + T::WeightInfo::migration_v2_pending_username_step(), + MigrationState::FinishedPendingUsernames | + MigrationState::CleanupAuthorities(_) => T::WeightInfo::migration_v2_cleanup_authority_step(), + MigrationState::FinishedCleanupAuthorities | + MigrationState::CleanupUsernames(_) => T::WeightInfo::migration_v2_cleanup_username_step(), + MigrationState::Finished => Weight::zero(), + } + } + + // Migrate one entry from `UsernameAuthorities` to `AuthorityOf`. + pub(crate) fn authority_step(maybe_last_key: Option<&T::AccountId>) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + types_v1::UsernameAuthorities::::iter_from( + types_v1::UsernameAuthorities::::hashed_key_for(last_key), + ) + } else { + types_v1::UsernameAuthorities::::iter() + }; + if let Some((authority_account, properties)) = iter.next() { + let suffix = properties.account_id; + let allocation = properties.allocation; + let new_properties = + AuthorityProperties { account_id: authority_account.clone(), allocation }; + AuthorityOf::::insert(&suffix, new_properties); + MigrationState::Authority(authority_account) + } else { + MigrationState::FinishedAuthorities + } + } + + // Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`. + pub(crate) fn username_step(maybe_last_key: Option<&Username>) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + types_v1::AccountOfUsername::::iter_from( + types_v1::AccountOfUsername::::hashed_key_for(last_key), + ) + } else { + types_v1::AccountOfUsername::::iter() + }; + + if let Some((username, owner_account)) = iter.next() { + let username_info = UsernameInformation { + owner: owner_account, + provider: Provider::new_with_allocation(), + }; + UsernameInfoOf::::insert(&username, username_info); + + MigrationState::Username(username) + } else { + MigrationState::FinishedUsernames + } + } + + // Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with + // it. Remove the entry if there was no real identity associated with the account. + pub(crate) fn identity_step(maybe_last_key: Option) -> StepResultOf { + if let Some(mut last_key) = + IdentityOf::::translate_next::< + ( + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + Option>, + ), + _, + >(maybe_last_key.map(|b| b.to_vec()), |account, (identity, maybe_username)| { + if let Some(primary_username) = maybe_username { + UsernameOf::::insert(&account, primary_username); + } + if identity.deposit > BalanceOf::::zero() { + Some(identity) + } else { + None + } + }) { + last_key.truncate(HashedKey::bound()); + MigrationState::Identity( + HashedKey::try_from(last_key) + .expect("truncated to bound so the conversion must succeed; qed"), + ) + } else { + MigrationState::FinishedIdentities + } + } + + // Migrate one entry from `PendingUsernames` to contain the new `Provider` field. + pub(crate) fn pending_username_step(maybe_last_key: Option) -> StepResultOf { + if let Some(mut last_key) = + PendingUsernames::::translate_next::<(T::AccountId, BlockNumberFor), _>( + maybe_last_key.map(|b| b.to_vec()), + |_, (owner_account, since)| { + Some((owner_account, since, Provider::new_with_allocation())) + }, + ) { + last_key.truncate(HashedKey::bound()); + MigrationState::PendingUsername( + HashedKey::try_from(last_key) + .expect("truncated to bound so the conversion must succeed; qed"), + ) + } else { + MigrationState::FinishedPendingUsernames + } + } + + // Remove one entry from `UsernameAuthorities`. + pub(crate) fn cleanup_authority_step( + maybe_last_key: Option<&Suffix>, + ) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + AuthorityOf::::iter_from(AuthorityOf::::hashed_key_for(last_key)) + } else { + AuthorityOf::::iter() + }; + + if let Some((suffix, properties)) = iter.next() { + let _ = types_v1::UsernameAuthorities::::take(&properties.account_id); + MigrationState::CleanupAuthorities(suffix) + } else { + MigrationState::FinishedCleanupAuthorities + } + } + + // Remove one entry from `AccountOfUsername`. + pub(crate) fn cleanup_username_step( + maybe_last_key: Option<&Username>, + ) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) + } else { + UsernameInfoOf::::iter() + }; + + if let Some((username, _)) = iter.next() { + let _ = types_v1::AccountOfUsername::::take(&username); + MigrationState::CleanupUsernames(username) + } else { + MigrationState::Finished + } + } + } + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) struct BenchmarkingSetup { + pub(crate) suffix: S, + pub(crate) authority: A, + pub(crate) account: A, + pub(crate) username: U, + } + + #[cfg(feature = "runtime-benchmarks")] + impl LazyMigrationV1ToV2 { + pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf { + use frame_support::Hashable; + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (®istration, Some(username.clone())), + ); + types_v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + frame_support::migration::put_storage_value( + b"Identity", + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), + ); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf { + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority, &prop); + let prop: AuthorityProperties = + AuthorityProperties { account_id: authority.clone(), allocation: 10 }; + AuthorityOf::::insert(&suffix, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + IdentityOf::::insert(&account_id, ®istration); + UsernameOf::::insert(&account_id, &username); + let username_info = UsernameInformation { + owner: account_id.clone(), + provider: Provider::new_with_allocation(), + }; + UsernameInfoOf::::insert(&username, username_info); + types_v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + PendingUsernames::::insert( + &username, + (&account_id, since, Provider::new_with_allocation()), + ); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn check_authority_cleanup_validity(suffix: Suffix, authority: T::AccountId) { + assert_eq!(types_v1::UsernameAuthorities::::iter().count(), 0); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().account_id, authority); + } + + pub(crate) fn check_username_cleanup_validity( + username: Username, + account_id: T::AccountId, + ) { + assert_eq!(types_v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(UsernameInfoOf::::get(&username).unwrap().owner, account_id); + } + } + + #[cfg(test)] + mod tests { + use frame_support::Hashable; + + use super::*; + use crate::tests::{new_test_ext, Test}; + + fn registration( + with_deposit: bool, + ) -> Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > { + Registration { + judgements: Default::default(), + deposit: if with_deposit { 10u32.into() } else { 0u32.into() }, + info: Default::default(), + } + } + + fn account_from_u8(byte: u8) -> ::AccountId { + [byte; 32].into() + } + + #[test] + fn migrate_to_v2() { + new_test_ext().execute_with(|| { + StorageVersion::new(1).put::>(); + // Set up the first authority. + let authority_1 = account_from_u8(151); + let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); + let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority_1, &prop); + // Set up the first authority. + let authority_2 = account_from_u8(152); + let suffix_2: Suffix = b"odd".to_vec().try_into().unwrap(); + let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority_2, &prop); + + // (owner_account, primary_username, maybe_secondary_username, has_identity) + // If `has_identity` is set, this `owner_account` will have a real identity + // associated and a non-zero deposit for it. + let mut usernames = vec![]; + for i in 0u8..100u8 { + let account_id = account_from_u8(i); + let bare_username = format!("acc{}.", i).as_bytes().to_vec(); + let mut username_1 = bare_username.clone(); + username_1.extend(suffix_1.iter()); + let username_1: Username = username_1.try_into().unwrap(); + types_v1::AccountOfUsername::::insert(&username_1, &account_id); + + if i % 2 == 0 { + let has_identity = i % 4 == 0; + let reg = registration(has_identity); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, Some(username_1.clone())), + ); + usernames.push((account_id, username_1, None, has_identity)); + } else { + let has_identity = i % 3 == 0; + let mut username_2 = bare_username.clone(); + username_2.extend(suffix_2.iter()); + let username_2: Username = username_2.try_into().unwrap(); + types_v1::AccountOfUsername::::insert(&username_2, &account_id); + let reg = registration(has_identity); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, Some(username_2.clone())), + ); + usernames.push((account_id, username_2, Some(username_1), has_identity)); + } + } + + // (username, owner_account, since) + let mut pending = vec![]; + for i in 100u8..110u8 { + let account_id = account_from_u8(i); + let mut bare_username = format!("acc{}.", i).as_bytes().to_vec(); + bare_username.extend(suffix_1.iter()); + let username: Username = bare_username.try_into().unwrap(); + let since: BlockNumberFor = i.into(); + frame_support::migration::put_storage_value( + b"Identity", + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), + ); + pending.push((username, account_id, since)); + } + + let mut identity_only = vec![]; + for i in 120u8..130u8 { + let account_id = account_from_u8(i); + let reg = registration(true); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, None::>), + ); + identity_only.push(account_id); + } + + // Run the actual migration. + let mut weight_meter = WeightMeter::new(); + let mut cursor = None; + while let Some(new_cursor) = + LazyMigrationV1ToV2::::step(cursor, &mut weight_meter).unwrap() + { + cursor = Some(new_cursor); + } + assert_eq!(Pallet::::on_chain_storage_version(), 2); + + // Check that the authorities were migrated. + let expected_prop = + AuthorityProperties { account_id: authority_1.clone(), allocation: 10 }; + assert_eq!(AuthorityOf::::get(&suffix_1), Some(expected_prop)); + + let expected_prop = + AuthorityProperties { account_id: authority_2.clone(), allocation: 10 }; + assert_eq!(AuthorityOf::::get(&suffix_2), Some(expected_prop)); + + // Check that the username information was migrated. + let count_of_usernames_without_identities = + usernames.iter().filter(|(_, _, _, has_id)| *has_id).count(); + assert_eq!(UsernameOf::::iter().count(), usernames.len()); + // All accounts have `evn` usernames, only half of them have `odd` usernames. + assert_eq!( + UsernameInfoOf::::iter().count(), + usernames.len() + usernames.len() / 2 + ); + for (owner, primary, maybe_secondary, has_identity) in usernames.iter() { + let username_info = UsernameInfoOf::::get(primary).unwrap(); + assert_eq!(&username_info.owner, owner); + let actual_primary = UsernameOf::::get(owner).unwrap(); + assert_eq!(primary, &actual_primary); + assert_eq!(IdentityOf::::contains_key(owner), *has_identity); + if let Some(secondary) = maybe_secondary { + let expected_info = UsernameInformation { + owner: owner.clone(), + provider: Provider::new_with_allocation(), + }; + assert_eq!(UsernameInfoOf::::get(secondary), Some(expected_info)); + } + } + + // Check that existing identities were preserved. + for id in identity_only.iter() { + let expected_reg = registration(true); + assert_eq!(IdentityOf::::get(id), Some(expected_reg)); + assert!(!UsernameOf::::contains_key(id)); + } + let identity_count = IdentityOf::::iter().count(); + assert_eq!( + identity_count, + count_of_usernames_without_identities + identity_only.len() + ); + + // Check that pending usernames were migrated. + let pending_count = PendingUsernames::::iter().count(); + assert_eq!(pending_count, pending.len()); + for (username, owner, since) in pending.iter() { + let expected_pending = (owner.clone(), *since, Provider::Allocation); + assert_eq!(PendingUsernames::::get(username), Some(expected_pending)); + } + + // Check that obsolete storage was cleared. + assert_eq!(types_v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(types_v1::UsernameAuthorities::::iter().count(), 0); + }); + } + } +} diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 3adb823ad5da..7bf5b2a72760 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -77,6 +77,7 @@ impl pallet_identity::Config for Test { type Slashed = (); type BasicDeposit = ConstU64<100>; type ByteDeposit = ConstU64<10>; + type UsernameDeposit = ConstU64<10>; type SubAccountDeposit = ConstU64<100>; type MaxSubAccounts = ConstU32<2>; type IdentityInformation = IdentityInfo; @@ -87,6 +88,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = AccountPublic; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU64<100>; + type UsernameGracePeriod = ConstU64<2>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); @@ -157,23 +159,21 @@ fn unfunded_accounts() -> [AccountIdOf; 2] { [account(100), account(101)] } -// First return value is a username that would be submitted as a parameter to the dispatchable. As -// in, it has no suffix attached. Second is a full BoundedVec username with suffix, which is what a -// user would need to sign. -fn test_username_of(int: Vec, suffix: Vec) -> (Vec, Username) { +// Returns a full BoundedVec username with suffix, which is what a user would need to sign. +fn test_username_of(int: Vec, suffix: Vec) -> Username { let base = b"testusername"; let mut username = Vec::with_capacity(base.len() + int.len()); username.extend(base); username.extend(int); let mut bounded_username = Vec::with_capacity(username.len() + suffix.len() + 1); - bounded_username.extend(username.clone()); + bounded_username.extend(username); bounded_username.extend(b"."); bounded_username.extend(suffix); let bounded_username = Username::::try_from(bounded_username) .expect("test usernames should fit within bounds"); - (username, bounded_username) + bounded_username } fn infoof_ten() -> IdentityInfo { @@ -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); @@ -401,7 +405,7 @@ fn registration_should_work() { RuntimeOrigin::signed(ten.clone()), Box::new(ten_info.clone()) )); - assert_eq!(IdentityOf::::get(ten.clone()).unwrap().0.info, ten_info); + assert_eq!(IdentityOf::::get(ten.clone()).unwrap().info, ten_info); assert_eq!(Balances::free_balance(ten.clone()), 1000 - id_deposit); assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(ten.clone()))); assert_eq!(Balances::free_balance(ten.clone()), 1000); @@ -485,7 +489,7 @@ fn uninvited_judgement_should_work() { identity_hash )); assert_eq!( - IdentityOf::::get(ten).unwrap().0.judgements, + IdentityOf::::get(ten).unwrap().judgements, vec![(0, Judgement::Reasonable)] ); }); @@ -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()), @@ -875,20 +886,14 @@ fn poke_deposit_works() { // Set a custom registration with 0 deposit IdentityOf::::insert::< _, - ( - Registration>, - Option>, - ), + Registration>, >( &ten, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: ten_info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, ); assert!(IdentityOf::::get(ten.clone()).is_some()); // Set a sub with zero deposit @@ -910,14 +915,11 @@ fn poke_deposit_works() { // new registration deposit is 10 assert_eq!( IdentityOf::::get(&ten), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit, - info: infoof_ten() - }, - None - )) + Some(Registration { + judgements: Default::default(), + deposit: id_deposit, + info: infoof_ten() + },) ); // new subs deposit is 10 vvvvvvvvvvvv assert_eq!(SubsOf::::get(ten), (subs_deposit, vec![twenty].try_into().unwrap())); @@ -932,20 +934,14 @@ fn poke_deposit_does_not_insert_new_subs_storage() { // Set a custom registration with 0 deposit IdentityOf::::insert::< _, - ( - Registration>, - Option>, - ), + Registration>, >( &ten, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: ten_info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, ); assert!(IdentityOf::::get(ten.clone()).is_some()); @@ -961,14 +957,11 @@ fn poke_deposit_does_not_insert_new_subs_storage() { // new registration deposit is 10 assert_eq!( IdentityOf::::get(&ten), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit, - info: infoof_ten() - }, - None - )) + Some(Registration { + judgements: Default::default(), + deposit: id_deposit, + info: infoof_ten() + }) ); // No new subs storage item. assert!(!SubsOf::::contains_key(&ten)); @@ -989,10 +982,11 @@ fn adding_and_removing_authorities_should_work() { suffix.clone(), allocation )); + let suffix: Suffix = suffix.try_into().unwrap(); assert_eq!( - UsernameAuthorities::::get(&authority), - Some(AuthorityPropertiesOf:: { - suffix: suffix.clone().try_into().unwrap(), + AuthorityOf::::get(&suffix), + Some(AuthorityProperties::> { + account_id: authority.clone(), allocation }) ); @@ -1001,20 +995,24 @@ fn adding_and_removing_authorities_should_work() { assert_ok!(Identity::add_username_authority( RuntimeOrigin::root(), authority.clone(), - suffix.clone(), + suffix.clone().into(), 11u32 )); assert_eq!( - UsernameAuthorities::::get(&authority), - Some(AuthorityPropertiesOf:: { - suffix: suffix.try_into().unwrap(), + AuthorityOf::::get(&suffix), + Some(AuthorityProperties::> { + account_id: authority.clone(), allocation: 11 }) ); // remove - assert_ok!(Identity::remove_username_authority(RuntimeOrigin::root(), authority.clone(),)); - assert!(UsernameAuthorities::::get(&authority).is_none()); + assert_ok!(Identity::remove_username_authority( + RuntimeOrigin::root(), + suffix.clone().into(), + authority.clone(), + )); + assert!(AuthorityOf::::get(&suffix).is_none()); }); } @@ -1022,7 +1020,9 @@ fn adding_and_removing_authorities_should_work() { fn set_username_with_signature_without_existing_identity_should_work() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, _] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1033,38 +1033,84 @@ fn set_username_with_signature_without_existing_identity_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix.clone()); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true, )); - // Even though user has no balance and no identity, they get a default one for free. + // Even though user has no balance and no identity, the authority provides the username for + // free. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // Lookup from username to account works. + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(username_to_sign.clone()) - )) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); + // No balance was reserved. + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // But the allocation decreased. + assert_eq!( + AuthorityOf::::get(&Identity::suffix_of_username(&username).unwrap()) + .unwrap() + .allocation, + 9 + ); + + // do the same for a username with a deposit + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + // set up username + let second_username = test_username_of(b"84".to_vec(), suffix.clone()); + + // set up user and sign message + let public = sr25519_generate(1.into(), None); + let second_who: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(1.into(), &public, &second_username[..]).unwrap()); + // don't use the allocation this time + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + second_who.clone(), + second_username.clone().into(), + Some(signature), + false, + )); + + // Even though user has no balance and no identity, the authority placed the deposit for + // them. + assert_eq!(UsernameOf::::get(&second_who), Some(second_username.clone())); // Lookup from username to account works. + let expected_user_info = UsernameInformation { + owner: second_who, + provider: Provider::AuthorityDeposit(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) + ); + // The username deposit was reserved. + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // But the allocation was preserved. assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) + AuthorityOf::::get(&Identity::suffix_of_username(&second_username).unwrap()) + .unwrap() + .allocation, + 9 ); }); } @@ -1084,14 +1130,13 @@ fn set_username_with_signature_with_existing_identity_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); // Set an identity for who. They need some balance though. Balances::make_free_balance_be(&who_account, 1000); @@ -1103,24 +1148,84 @@ fn set_username_with_signature_with_existing_identity_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true, )); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit(&ten_info), - info: ten_info - }, - Some(username_to_sign.clone()) - )) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); + }); +} + +#[test] +fn set_username_through_deposit_with_existing_identity_should_work() { + new_test_ext().execute_with(|| { + // set up authority + let initial_authority_balance = 1000; + let [authority, _] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + // set up username + let username = test_username_of(b"42".to_vec(), suffix); + + // set up user and sign message + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + let ten_info = infoof_ten(); + let expected_identity_deposit = Identity::calculate_identity_deposit(&ten_info); + assert_ok!(Identity::set_identity( + RuntimeOrigin::signed(who_account.clone()), + Box::new(ten_info.clone()) + )); assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) + expected_identity_deposit, + IdentityOf::::get(&who_account).unwrap().deposit + ); + assert_eq!(Balances::reserved_balance(&who_account), expected_identity_deposit); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false, + )); + + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + // The authority placed the deposit for the username. + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // No extra balance was reserved from the user for the username. + assert_eq!(Balances::free_balance(&who_account), 1000 - expected_identity_deposit); + assert_eq!(Balances::reserved_balance(&who_account), expected_identity_deposit); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + let expected_user_info = UsernameInformation { + owner: who_account, + provider: Provider::AuthorityDeposit(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); }); } @@ -1144,8 +1249,8 @@ fn set_username_with_bytes_signature_should_work() { let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); - let unwrapped_username = username_to_sign.to_vec(); + let username = test_username_of(b"42".to_vec(), suffix); + let unwrapped_username = username.to_vec(); // Sign an unwrapped version, as in `username.suffix`. let signature_on_unwrapped = MultiSignature::Sr25519( @@ -1184,27 +1289,20 @@ fn set_username_with_bytes_signature_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username, - Some(signature_on_wrapped) + username.clone().into(), + Some(signature_on_wrapped), + true, )); // The username in storage should not include ``. As in, it's the original // `username_to_sign`. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(username_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Likewise for the lookup. + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); }); } @@ -1213,7 +1311,9 @@ fn set_username_with_bytes_signature_should_work() { fn set_username_with_acceptance_should_work() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1224,45 +1324,82 @@ fn set_username_with_acceptance_should_work() { )); // set up username - let (username, full_username) = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix.clone()); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who.clone(), - username.clone(), - None + username.clone().into(), + None, + true, )); // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&full_username), - Some((who.clone(), expiration)) + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Allocation)) + ); + + // Now the user can accept + assert_ok!(Identity::accept_username(RuntimeOrigin::signed(who.clone()), username.clone())); + + // No more pending + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + // Check Identity storage + assert_eq!(UsernameOf::::get(&who), Some(username.clone())); + // Check reverse lookup + let expected_user_info = UsernameInformation { owner: who, provider: Provider::Allocation }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + + let second_caller = account(99); + let second_username = test_username_of(b"102".to_vec(), suffix); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + second_caller.clone(), + second_username.clone().into(), + None, + false, + )); + // Should be pending + let username_deposit = ::UsernameDeposit::get(); + assert_eq!( + PendingUsernames::::get::<&Username>(&second_username), + Some((second_caller.clone(), expiration, Provider::AuthorityDeposit(username_deposit))) + ); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); // Now the user can accept assert_ok!(Identity::accept_username( - RuntimeOrigin::signed(who.clone()), - full_username.clone() + RuntimeOrigin::signed(second_caller.clone()), + second_username.clone() )); // No more pending - assert!(PendingUsernames::::get::<&Username>(&full_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&second_username).is_none()); // Check Identity storage + assert_eq!(UsernameOf::::get(&second_caller), Some(second_username.clone())); + // Check reverse lookup + let expected_user_info = UsernameInformation { + owner: second_caller, + provider: Provider::AuthorityDeposit(username_deposit), + }; assert_eq!( - IdentityOf::::get(&who), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(full_username.clone()) - )) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) + ); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit ); - // Check reverse lookup - assert_eq!(AccountOfUsername::::get::<&Username>(&full_username), Some(who)); }); } @@ -1295,7 +1432,7 @@ fn invalid_usernames_should_be_rejected() { assert_ok!(Identity::add_username_authority( RuntimeOrigin::root(), authority.clone(), - valid_suffix, + valid_suffix.clone(), allocation )); @@ -1311,25 +1448,33 @@ fn invalid_usernames_should_be_rejected() { //0 1 2 v With `.test` this makes it too long. b"testusernametestusernametest".to_vec(), ]; - for username in invalid_usernames { + for username in invalid_usernames.into_iter().map(|mut username| { + username.push(b'.'); + username.extend(valid_suffix.clone()); + username + }) { assert_noop!( Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who.clone(), username.clone(), - None + None, + true, ), Error::::InvalidUsername ); } // valid one works - let valid_username = b"testusernametestusernametes".to_vec(); + let mut valid_username = b"testusernametestusernametes".to_vec(); + valid_username.push(b'.'); + valid_username.extend(valid_suffix); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who, valid_username, - None + None, + true, )); }); } @@ -1352,21 +1497,24 @@ fn authorities_should_run_out_of_allocation() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), pi, - b"username314159".to_vec(), - None + b"username314159.test".to_vec(), + None, + true, )); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), e, - b"username271828".to_vec(), - None + b"username271828.test".to_vec(), + None, + true )); assert_noop!( Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), c, - b"username299792458".to_vec(), - None + b"username299792458.test".to_vec(), + None, + true, ), Error::::NoAllocation ); @@ -1392,91 +1540,65 @@ fn setting_primary_should_work() { let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // set up username - let (first_username, first_to_sign) = test_username_of(b"42".to_vec(), suffix.clone()); + let first_username = test_username_of(b"42".to_vec(), suffix.clone()); let first_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &first_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &first_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who_account.clone(), - first_username.clone(), - Some(first_signature) + first_username.clone().into(), + Some(first_signature), + true )); // First username set as primary. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(first_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // set up username - let (second_username, second_to_sign) = test_username_of(b"101".to_vec(), suffix); + let second_username = test_username_of(b"101".to_vec(), suffix); let second_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &second_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &second_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - second_username.clone(), - Some(second_signature) + second_username.clone().into(), + Some(second_signature), + true, )); // The primary is still the first username. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(first_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // Lookup from both works. + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&first_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&first_username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info.clone()) ); assert_ok!(Identity::set_primary_username( RuntimeOrigin::signed(who_account.clone()), - second_to_sign.clone() + second_username.clone() )); // The primary is now the second username. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(second_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(second_username.clone())); // Lookup from both still works. assert_eq!( - AccountOfUsername::::get::<&Username>(&first_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&first_username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_to_sign), - Some(who_account) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) ); }); } @@ -1498,60 +1620,67 @@ fn must_own_primary() { // Set up first user ("pi") and a username. let pi_public = sr25519_generate(0.into(), None); let pi_account: AccountIdOf = MultiSigner::Sr25519(pi_public).into_account().into(); - let (pi_username, pi_to_sign) = - test_username_of(b"username314159".to_vec(), suffix.clone()); + let pi_username = test_username_of(b"username314159".to_vec(), suffix.clone()); let pi_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &pi_public, &pi_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &pi_public, &pi_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), pi_account.clone(), - pi_username.clone(), - Some(pi_signature) + pi_username.clone().into(), + Some(pi_signature), + true, )); // Set up second user ("e") and a username. let e_public = sr25519_generate(1.into(), None); let e_account: AccountIdOf = MultiSigner::Sr25519(e_public).into_account().into(); - let (e_username, e_to_sign) = test_username_of(b"username271828".to_vec(), suffix.clone()); + let e_username = test_username_of(b"username271828".to_vec(), suffix.clone()); let e_signature = - MultiSignature::Sr25519(sr25519_sign(1.into(), &e_public, &e_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(1.into(), &e_public, &e_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), e_account.clone(), - e_username.clone(), - Some(e_signature) + e_username.clone().into(), + Some(e_signature), + true )); // Ensure that both users have their usernames. + let expected_pi_info = + UsernameInformation { owner: pi_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&pi_to_sign), - Some(pi_account.clone()) + UsernameInfoOf::::get::<&Username>(&pi_username), + Some(expected_pi_info) ); + let expected_e_info = + UsernameInformation { owner: e_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&e_to_sign), - Some(e_account.clone()) + UsernameInfoOf::::get::<&Username>(&e_username), + Some(expected_e_info) ); // Cannot set primary to a username that does not exist. - let (_, c_username) = test_username_of(b"speedoflight".to_vec(), suffix.clone()); + let c_username = test_username_of(b"speedoflight".to_vec(), suffix.clone()); assert_err!( - Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), c_username,), + Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), c_username), Error::::NoUsername ); // Cannot take someone else's username as your primary. assert_err!( - Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), e_to_sign,), + Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), e_username), Error::::InvalidUsername ); }); } #[test] -fn unaccepted_usernames_should_expire() { +fn unaccepted_usernames_through_grant_should_expire() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1562,31 +1691,34 @@ fn unaccepted_usernames_should_expire() { )); // set up username - let (username, full_username) = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix.clone()); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); + let suffix: Suffix = suffix.try_into().unwrap(); + + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who.clone(), - username.clone(), - None + username.clone().into(), + None, + true, )); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&full_username), - Some((who.clone(), expiration)) + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Allocation)) ); run_to_block(now + expiration - 1); // Cannot be removed assert_noop!( - Identity::remove_expired_approval( - RuntimeOrigin::signed(account(1)), - full_username.clone() - ), + Identity::remove_expired_approval(RuntimeOrigin::signed(account(1)), username.clone()), Error::::NotExpired ); @@ -1595,19 +1727,24 @@ fn unaccepted_usernames_should_expire() { // Anyone can remove assert_ok!(Identity::remove_expired_approval( RuntimeOrigin::signed(account(1)), - full_username.clone() + username.clone() )); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // Allocation wasn't refunded + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // No more pending - assert!(PendingUsernames::::get::<&Username>(&full_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); }); } #[test] -fn removing_dangling_usernames_should_work() { +fn unaccepted_usernames_through_deposit_should_expire() { new_test_ext().execute_with(|| { // set up authority - let [authority, caller] = unfunded_accounts(); + let initial_authority_balance = 1000; + let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1618,98 +1755,494 @@ fn removing_dangling_usernames_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix.clone()); + let username = test_username_of(b"101".to_vec(), suffix.clone()); + let now = frame_system::Pallet::::block_number(); + let expiration = now + <::PendingUsernameExpiration as Get>::get(); + + let suffix: Suffix = suffix.try_into().unwrap(); + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who.clone(), + username.clone().into(), + None, + false, + )); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + + // Should be pending + assert_eq!( + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::AuthorityDeposit(username_deposit))) + ); + + run_to_block(now + expiration - 1); + + // Cannot be removed + assert_noop!( + Identity::remove_expired_approval(RuntimeOrigin::signed(account(1)), username.clone()), + Error::::NotExpired + ); + + run_to_block(now + expiration); + + // Anyone can remove + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + assert_eq!(Balances::reserved_balance(&authority), username_deposit); + assert_ok!(Identity::remove_expired_approval( + RuntimeOrigin::signed(account(1)), + username.clone() + )); + // Deposit was refunded + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // Allocation wasn't refunded + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + + // No more pending + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + }); +} + +#[test] +fn kill_username_should_work() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // set up first authority + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let second_authority = account(200); + Balances::make_free_balance_be(&second_authority, initial_authority_balance); + let second_suffix: Vec = b"abc".to_vec(); + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + second_authority.clone(), + second_suffix.clone(), + allocation + )); + + let username_deposit = ::UsernameDeposit::get(); + + // set up username + let username = test_username_of(b"42".to_vec(), suffix.clone()); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); // Set an identity for who. They need some balance though. Balances::make_free_balance_be(&who_account, 1000); - let ten_info = infoof_ten(); - assert_ok!(Identity::set_identity( - RuntimeOrigin::signed(who_account.clone()), - Box::new(ten_info.clone()) - )); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + false )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); // Now they set up a second username. - let (username_two, username_two_to_sign) = test_username_of(b"43".to_vec(), suffix); + let username_two = test_username_of(b"43".to_vec(), suffix.clone()); // set up user and sign message - let signature_two = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_two_to_sign[..]).unwrap(), + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username_two.clone().into(), + Some(signature_two), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - 2 * username_deposit ); + // Now they set up a third username with another authority. + let username_three = test_username_of(b"42".to_vec(), second_suffix.clone()); + + // set up user and sign message + let signature_three = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_three[..]).unwrap()); + assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(second_authority.clone()), who_account.clone(), - username_two.clone(), - Some(signature_two) + username_three.clone().into(), + Some(signature_three), + true )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - 2 * username_deposit + ); + assert_eq!(Balances::free_balance(second_authority.clone()), initial_authority_balance); // The primary should still be the first one. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + + // But both usernames should look up the account. + let expected_user_info = UsernameInformation { + owner: who_account.clone(), + provider: Provider::AuthorityDeposit(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) + ); + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) + ); + + // Regular accounts can't kill a username, not even the authority that granted it. + assert_noop!( + Identity::kill_username(RuntimeOrigin::signed(authority.clone()), username.clone()), + BadOrigin + ); + + // Can't kill a username that doesn't exist. + assert_noop!( + Identity::kill_username( + RuntimeOrigin::root(), + test_username_of(b"999".to_vec(), suffix.clone()) + ), + Error::::NoUsername + ); + + // Unbind the second username. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username_two.clone() + )); + + // Kill the second username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username_two.clone().into())); + + // The reverse lookup of the primary is gone. + assert!(UsernameInfoOf::::get::<&Username>(&username_two).is_none()); + // The unbinding map entry is gone. + assert!(UnbindingUsernames::::get::<&Username>(&username).is_none()); + // The authority's deposit was slashed. + assert_eq!(Balances::reserved_balance(authority.clone()), username_deposit); + + // But the reverse lookup of the primary is still there + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + assert!(UsernameInfoOf::::contains_key(&username_three)); + + // Kill the first, primary username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username.clone().into())); + + // The reverse lookup of the primary is gone. + assert!(UsernameInfoOf::::get::<&Username>(&username).is_none()); + assert!(!UsernameOf::::contains_key(&who_account)); + // The authority's deposit was slashed. + assert_eq!(Balances::reserved_balance(authority.clone()), 0); + + // But the reverse lookup of the third and final username is still there + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_three), + Some(expected_user_info) + ); + + // Kill the third and last username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username_three.clone().into())); + // Everything is gone. + assert!(!UsernameInfoOf::::contains_key(&username_three)); + }); +} + +#[test] +fn unbind_and_remove_username_should_work() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // Set up authority. + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let username_deposit = ::UsernameDeposit::get(); + + // Set up username. + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // Set up user and sign message. + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // Now they set up a second username. + let username_two = test_username_of(b"43".to_vec(), suffix.clone()); + + // Set up user and sign message. + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username_two.clone().into(), + Some(signature_two), + true + )); + // Second one is free. assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit(&ten_info), - info: ten_info - }, - Some(username_to_sign.clone()) - )) + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit ); + // The primary should still be the first one. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // But both usernames should look up the account. + let expected_user_info = UsernameInformation { + owner: who_account.clone(), + provider: Provider::AuthorityDeposit(username_deposit), + }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) ); + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) ); - // Someone tries to remove it, but they can't + // Regular accounts can't kill a username, not even the authority that granted it. assert_noop!( - Identity::remove_dangling_username( - RuntimeOrigin::signed(caller.clone()), - username_to_sign.clone() + Identity::kill_username(RuntimeOrigin::signed(authority.clone()), username.clone()), + BadOrigin + ); + + // Can't unbind a username that doesn't exist. + let dummy_suffix = b"abc".to_vec(); + let dummy_username = test_username_of(b"999".to_vec(), dummy_suffix.clone()); + let dummy_authority = account(78); + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(dummy_authority.clone()), + dummy_username.clone() ), - Error::::InvalidUsername + Error::::NoUsername ); - // Now the user calls `clear_identity` - assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(who_account.clone()),)); + let dummy_suffix: Suffix = dummy_suffix.try_into().unwrap(); + // Only the authority that granted the username can unbind it. + UsernameInfoOf::::insert( + dummy_username.clone(), + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }, + ); + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(dummy_authority.clone()), + dummy_username.clone() + ), + Error::::NotUsernameAuthority + ); + // Simulate a dummy authority. + AuthorityOf::::insert( + dummy_suffix.clone(), + AuthorityProperties { account_id: dummy_authority.clone(), allocation: 10 }, + ); + // But try to remove the dummy username as a different authority, not the one that + // originally granted the username. + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + dummy_username.clone() + ), + Error::::NotUsernameAuthority + ); + // Clean up storage. + let _ = UsernameInfoOf::::take(dummy_username.clone()); + let _ = AuthorityOf::::take(dummy_suffix); - // Identity is gone - assert!(IdentityOf::::get(who_account.clone()).is_none()); + // We can successfully unbind the username as the authority that granted it. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username_two.clone() + )); + let grace_period: BlockNumberFor = ::UsernameGracePeriod::get(); + let now = 1; + assert_eq!(System::block_number(), now); + let expected_grace_period_expiry: BlockNumberFor = now + grace_period; + assert_eq!( + UnbindingUsernames::::get(&username_two), + Some(expected_grace_period_expiry) + ); - // The reverse lookup of the primary is gone. - assert!(AccountOfUsername::::get::<&Username>(&username_to_sign).is_none()); + // Still in the grace period. + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username_two.clone()), + Error::::TooEarly + ); - // But the reverse lookup of the non-primary is still there + // Advance the block number to simulate the grace period passing. + System::set_block_number(expected_grace_period_expiry); + + let suffix: Suffix = suffix.try_into().unwrap(); + // We can now remove the username from any account. + assert_ok!(Identity::remove_username( + RuntimeOrigin::signed(account(0)), + username_two.clone() + )); + // The username is gone. + assert!(!UnbindingUsernames::::contains_key(&username_two)); + assert!(!UsernameInfoOf::::contains_key(&username_two)); + // Primary username was preserved. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // The username was granted through a governance allocation, so no deposit was released. assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two_to_sign), - Some(who_account) + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit ); + // Allocation wasn't refunded. + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); - // Now it can be removed - assert_ok!(Identity::remove_dangling_username( - RuntimeOrigin::signed(caller), - username_two_to_sign.clone() + // Unbind the first username as well. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username.clone() + )); + let now: BlockNumberFor = expected_grace_period_expiry; + assert_eq!(System::block_number(), now); + let expected_grace_period_expiry: BlockNumberFor = now + grace_period; + assert_eq!(UnbindingUsernames::::get(&username), Some(expected_grace_period_expiry)); + // Advance the block number to simulate the grace period passing. + System::set_block_number(expected_grace_period_expiry); + // We can now remove the username from any account. + assert_ok!(Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone())); + // The username is gone. + assert!(!UnbindingUsernames::::contains_key(&username)); + assert!(!UsernameInfoOf::::contains_key(&username)); + // Primary username was also removed. + assert!(!UsernameOf::::contains_key(&who_account)); + // The username deposit was released. + assert_eq!(Balances::free_balance(authority.clone()), initial_authority_balance); + // Allocation didn't change. + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); + }); +} + +#[test] +#[should_panic] +fn unbind_dangling_username_defensive_should_panic() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // Set up authority. + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + + // Set up username. + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // Set up user and sign message. + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); - // And the reverse lookup is gone - assert!(AccountOfUsername::::get::<&Username>(&username_two_to_sign).is_none()); + // We can successfully unbind the username as the authority that granted it. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username.clone() + )); + assert_eq!(System::block_number(), 1); + assert_eq!(UnbindingUsernames::::get(&username), Some(1)); + + // Still in the grace period. + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone()), + Error::::TooEarly + ); + + // Advance the block number to simulate the grace period passing. + System::set_block_number(3); + + // Simulate a dangling entry in the unbinding map without an actual username registered. + UsernameInfoOf::::remove(&username); + UsernameOf::::remove(&who_account); + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone()), + Error::::NoUsername + ); }); } diff --git a/substrate/frame/identity/src/types.rs b/substrate/frame/identity/src/types.rs index 45401d53e9e9..ece3c34f82ef 100644 --- a/substrate/frame/identity/src/types.rs +++ b/substrate/frame/identity/src/types.rs @@ -320,9 +320,6 @@ pub struct RegistrarInfo< pub fields: IdField, } -/// Authority properties for a given pallet configuration. -pub type AuthorityPropertiesOf = AuthorityProperties>; - /// The number of usernames that an authority may allocate. type Allocation = u32; /// A byte vec used to represent a username. @@ -330,11 +327,9 @@ pub(crate) type Suffix = BoundedVec::MaxSuffixLength>; /// Properties of a username authority. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] -pub struct AuthorityProperties { - /// The suffix added to usernames granted by this authority. Will be appended to usernames; for - /// example, a suffix of `wallet` will result in `.wallet` being appended to a user's selected - /// name. - pub suffix: Suffix, +pub struct AuthorityProperties { + /// The account of the authority. + pub account_id: Account, /// The number of usernames remaining that this authority can grant. pub allocation: Allocation, } @@ -342,6 +337,34 @@ pub struct AuthorityProperties { /// A byte vec used to represent a username. pub(crate) type Username = BoundedVec::MaxUsernameLength>; +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] +pub enum Provider { + Allocation, + AuthorityDeposit(Balance), + System, +} + +impl Provider { + pub fn new_with_allocation() -> Self { + Self::Allocation + } + + pub fn new_with_deposit(deposit: Balance) -> Self { + Self::AuthorityDeposit(deposit) + } + + #[allow(unused)] + pub fn new_permanent() -> Self { + Self::System + } +} + +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] +pub struct UsernameInformation { + pub owner: Account, + pub provider: Provider, +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 008d5465bb4f..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,11 +69,19 @@ pub trait WeightInfo { fn quit_sub(s: u32, ) -> Weight; fn add_username_authority() -> Weight; fn remove_username_authority() -> Weight; - fn set_username_for() -> Weight; + fn set_username_for(p: u32, ) -> Weight; fn accept_username() -> Weight; - fn remove_expired_approval() -> Weight; + fn remove_expired_approval(p: u32, ) -> Weight; fn set_primary_username() -> Weight; - fn remove_dangling_username() -> Weight; + fn unbind_username() -> Weight; + fn remove_username() -> 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; + fn migration_v2_pending_username_step() -> Weight; + fn migration_v2_cleanup_authority_step() -> Weight; + fn migration_v2_cleanup_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -86,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) @@ -117,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)) @@ -129,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) @@ -138,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()))) @@ -150,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()))) @@ -172,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)) } @@ -206,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)) } @@ -220,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)) } @@ -234,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) @@ -269,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) @@ -291,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) @@ -325,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)) } @@ -344,103 +352,226 @@ 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() -> 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() -> 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: `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::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: `115` - // Estimated: `3550` - // Minimum execution time: 16_880_000 picoseconds. - Weight::from_parts(28_371_000, 3550) + // 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::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`) - fn set_primary_username() -> Weight { + /// 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 { + // 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 { + // 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)) + } + /// 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: `257` - // Estimated: `11037` - // Minimum execution time: 16_771_000 picoseconds. - Weight::from_parts(17_333_000, 11037) + // 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 { + // 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: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { + /// 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 { + // 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 { + // 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 { // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 12_017_000 picoseconds. - Weight::from_parts(12_389_000, 11037) + // 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 { + // 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 { + // 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)) + } } // For backwards compatibility and tests. @@ -452,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) @@ -483,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)) @@ -495,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) @@ -504,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()))) @@ -516,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()))) @@ -538,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)) } @@ -572,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)) } @@ -586,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)) } @@ -600,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) @@ -635,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) @@ -657,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) @@ -691,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)) } @@ -710,101 +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() -> 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() -> 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: `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::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: `115` - // Estimated: `3550` - // Minimum execution time: 16_880_000 picoseconds. - Weight::from_parts(28_371_000, 3550) + // 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::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`) - fn set_primary_username() -> Weight { + /// 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 { + // 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 { + // 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)) + } + /// 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: `257` - // Estimated: `11037` - // Minimum execution time: 16_771_000 picoseconds. - Weight::from_parts(17_333_000, 11037) + // 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 { + // 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: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { + /// 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 { + // 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 { + // 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 { // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 12_017_000 picoseconds. - Weight::from_parts(12_389_000, 11037) + // 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 { + // 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 { + // 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/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/lib.rs b/substrate/frame/im-online/src/lib.rs index ee2a8451d6fb..74d3bc6484dd 100644 --- a/substrate/frame/im-online/src/lib.rs +++ b/substrate/frame/im-online/src/lib.rs @@ -95,7 +95,7 @@ use frame_support::{ BoundedSlice, WeakBoundedVec, }; use frame_system::{ - offchain::{SendTransactionTypes, SubmitTransaction}, + offchain::{CreateInherent, SubmitTransaction}, pallet_prelude::*, }; pub use pallet::*; @@ -261,7 +261,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: SendTransactionTypes> + frame_system::Config { + pub trait Config: CreateInherent> + frame_system::Config { /// The identifier type for an authority. type AuthorityId: Member + Parameter @@ -642,7 +642,8 @@ impl Pallet { call, ); - SubmitTransaction::>::submit_unsigned_transaction(call.into()) + let xt = T::create_inherent(call.into()); + SubmitTransaction::>::submit_transaction(xt) .map_err(|_| OffchainErr::SubmitTransaction)?; Ok(()) diff --git a/substrate/frame/im-online/src/mock.rs b/substrate/frame/im-online/src/mock.rs index 882581702ea1..a5d9a6e20e61 100644 --- a/substrate/frame/im-online/src/mock.rs +++ b/substrate/frame/im-online/src/mock.rs @@ -25,11 +25,7 @@ use frame_support::{ weights::Weight, }; use pallet_session::historical as pallet_session_historical; -use sp_runtime::{ - testing::{TestXt, UintAuthorityId}, - traits::ConvertInto, - BuildStorage, Permill, -}; +use sp_runtime::{testing::UintAuthorityId, traits::ConvertInto, BuildStorage, Permill}; use sp_staking::{ offence::{OffenceError, ReportOffence}, SessionIndex, @@ -77,7 +73,7 @@ impl pallet_session::historical::SessionManager for TestSessionManager } /// An extrinsic type used for tests. -pub type Extrinsic = TestXt; +pub type Extrinsic = sp_runtime::testing::TestXt; type IdentificationTuple = (u64, u64); type Offence = crate::UnresponsivenessOffence; @@ -191,14 +187,23 @@ impl Config for Runtime { type MaxPeerInHeartbeats = ConstU32<10_000>; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } +} + pub fn advance_session() { let now = System::block_number().max(1); System::set_block_number(now + 1); diff --git a/substrate/frame/im-online/src/tests.rs b/substrate/frame/im-online/src/tests.rs index 12333d59ef89..b9a2772da689 100644 --- a/substrate/frame/im-online/src/tests.rs +++ b/substrate/frame/im-online/src/tests.rs @@ -225,7 +225,7 @@ fn should_generate_heartbeats() { // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); - let heartbeat = match ex.call { + let heartbeat = match ex.function { crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, e => panic!("Unexpected call: {:?}", e), @@ -339,7 +339,7 @@ fn should_not_send_a_report_if_already_online() { assert_eq!(pool_state.read().transactions.len(), 0); // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); - let heartbeat = match ex.call { + let heartbeat = match ex.function { crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, e => panic!("Unexpected call: {:?}", e), 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/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/lottery/src/lib.rs b/substrate/frame/lottery/src/lib.rs index 0071b258fc45..6a15de55ebd7 100644 --- a/substrate/frame/lottery/src/lib.rs +++ b/substrate/frame/lottery/src/lib.rs @@ -300,7 +300,7 @@ pub mod pallet { #[pallet::call_index(0)] #[pallet::weight( T::WeightInfo::buy_ticket() - .saturating_add(call.get_dispatch_info().weight) + .saturating_add(call.get_dispatch_info().call_weight) )] pub fn buy_ticket( origin: OriginFor, 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/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/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 48002acb1474..04620fa88d85 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -649,7 +649,7 @@ pub mod pallet { impl Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { if let Some(weight_limit) = T::ServiceWeight::get() { - Self::service_queues(weight_limit) + Self::service_queues_impl(weight_limit, ServiceQueuesContext::OnInitialize) } else { Weight::zero() } @@ -658,7 +658,10 @@ pub mod pallet { fn on_idle(_n: BlockNumberFor, remaining_weight: Weight) -> Weight { if let Some(weight_limit) = T::IdleMaxServiceWeight::get() { // Make use of the remaining weight to process enqueued messages. - Self::service_queues(weight_limit.min(remaining_weight)) + Self::service_queues_impl( + weight_limit.min(remaining_weight), + ServiceQueuesContext::OnIdle, + ) } else { Weight::zero() } @@ -777,6 +780,18 @@ enum MessageExecutionStatus { StackLimitReached, } +/// The context to pass to [`Pallet::service_queues_impl`] through on_idle and on_initialize hooks +/// We don't want to throw the defensive message if called from on_idle hook +#[derive(PartialEq)] +enum ServiceQueuesContext { + /// Context of on_idle hook. + OnIdle, + /// Context of on_initialize hook. + OnInitialize, + /// Context `service_queues` trait function. + ServiceQueues, +} + impl Pallet { /// Knit `origin` into the ready ring right at the end. /// @@ -853,13 +868,26 @@ impl Pallet { } } - /// The maximal weight that a single message can consume. + /// The maximal weight that a single message ever can consume. /// /// Any message using more than this will be marked as permanently overweight and not /// automatically re-attempted. Returns `None` if the servicing of a message cannot begin. /// `Some(0)` means that only messages with no weight may be served. fn max_message_weight(limit: Weight) -> Option { - limit.checked_sub(&Self::single_msg_overhead()) + let service_weight = T::ServiceWeight::get().unwrap_or_default(); + let on_idle_weight = T::IdleMaxServiceWeight::get().unwrap_or_default(); + + // Whatever weight is set, the one with the biggest one is used as the maximum weight. If a + // message is tried in one context and fails, it will be retried in the other context later. + let max_message_weight = + if service_weight.any_gt(on_idle_weight) { service_weight } else { on_idle_weight }; + + if max_message_weight.is_zero() { + // If no service weight is set, we need to use the given limit as max message weight. + limit.checked_sub(&Self::single_msg_overhead()) + } else { + max_message_weight.checked_sub(&Self::single_msg_overhead()) + } } /// The overhead of servicing a single message. @@ -881,6 +909,8 @@ impl Pallet { fn do_integrity_test() -> Result<(), String> { ensure!(!MaxMessageLenOf::::get().is_zero(), "HeapSize too low"); + let max_block = T::BlockWeights::get().max_block; + if let Some(service) = T::ServiceWeight::get() { if Self::max_message_weight(service).is_none() { return Err(format!( @@ -889,6 +919,31 @@ impl Pallet { Self::single_msg_overhead(), )) } + + if service.any_gt(max_block) { + return Err(format!( + "ServiceWeight {service} is bigger than max block weight {max_block}" + )) + } + } + + if let Some(on_idle) = T::IdleMaxServiceWeight::get() { + if on_idle.any_gt(max_block) { + return Err(format!( + "IdleMaxServiceWeight {on_idle} is bigger than max block weight {max_block}" + )) + } + } + + if let (Some(service_weight), Some(on_idle)) = + (T::ServiceWeight::get(), T::IdleMaxServiceWeight::get()) + { + if !(service_weight.all_gt(on_idle) || + on_idle.all_gt(service_weight) || + service_weight == on_idle) + { + return Err("One of `ServiceWeight` or `IdleMaxServiceWeight` needs to be `all_gt` or both need to be equal.".into()) + } } Ok(()) @@ -1511,6 +1566,54 @@ impl Pallet { }, } } + + fn service_queues_impl(weight_limit: Weight, context: ServiceQueuesContext) -> Weight { + let mut weight = WeightMeter::with_limit(weight_limit); + + // Get the maximum weight that processing a single message may take: + let overweight_limit = Self::max_message_weight(weight_limit).unwrap_or_else(|| { + if matches!(context, ServiceQueuesContext::OnInitialize) { + defensive!("Not enough weight to service a single message."); + } + Weight::zero() + }); + + match with_service_mutex(|| { + let mut next = match Self::bump_service_head(&mut weight) { + Some(h) => h, + None => return weight.consumed(), + }; + // The last queue that did not make any progress. + // The loop aborts as soon as it arrives at this queue again without making any progress + // on other queues in between. + let mut last_no_progress = None; + + loop { + let (progressed, n) = + Self::service_queue(next.clone(), &mut weight, overweight_limit); + next = match n { + Some(n) => + if !progressed { + if last_no_progress == Some(n.clone()) { + break + } + if last_no_progress.is_none() { + last_no_progress = Some(next.clone()) + } + n + } else { + last_no_progress = None; + n + }, + None => break, + } + } + weight.consumed() + }) { + Err(()) => weight.consumed(), + Ok(w) => w, + } + } } /// Run a closure that errors on re-entrance. Meant to be used by anything that services queues. @@ -1580,48 +1683,7 @@ impl ServiceQueues for Pallet { type OverweightMessageAddress = (MessageOriginOf, PageIndex, T::Size); fn service_queues(weight_limit: Weight) -> Weight { - let mut weight = WeightMeter::with_limit(weight_limit); - - // Get the maximum weight that processing a single message may take: - let max_weight = Self::max_message_weight(weight_limit).unwrap_or_else(|| { - defensive!("Not enough weight to service a single message."); - Weight::zero() - }); - - match with_service_mutex(|| { - let mut next = match Self::bump_service_head(&mut weight) { - Some(h) => h, - None => return weight.consumed(), - }; - // The last queue that did not make any progress. - // The loop aborts as soon as it arrives at this queue again without making any progress - // on other queues in between. - let mut last_no_progress = None; - - loop { - let (progressed, n) = Self::service_queue(next.clone(), &mut weight, max_weight); - next = match n { - Some(n) => - if !progressed { - if last_no_progress == Some(n.clone()) { - break - } - if last_no_progress.is_none() { - last_no_progress = Some(next.clone()) - } - n - } else { - last_no_progress = None; - n - }, - None => break, - } - } - weight.consumed() - }) { - Err(()) => weight.consumed(), - Ok(w) => w, - } + Self::service_queues_impl(weight_limit, ServiceQueuesContext::ServiceQueues) } /// Execute a single overweight message. diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index d3f719c62356..f1d341d1a5db 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -42,7 +42,7 @@ impl frame_system::Config for Test { type Block = Block; } parameter_types! { - pub const HeapSize: u32 = 24; + pub const HeapSize: u32 = 40; pub const MaxStale: u32 = 2; pub const ServiceWeight: Option = Some(Weight::from_parts(100, 100)); } diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index fac135f135ce..c81e486a40df 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -177,7 +177,7 @@ fn service_queues_failing_messages_works() { MessageQueue::enqueue_message(msg("stacklimitreached"), Here); MessageQueue::enqueue_message(msg("yield"), Here); // Starts with four pages. - assert_pages(&[0, 1, 2, 3, 4]); + assert_pages(&[0, 1, 2]); assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_last_event::( @@ -209,7 +209,7 @@ fn service_queues_failing_messages_works() { assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_eq!(System::events().len(), 4); // Last page with the `yield` stays in. - assert_pages(&[4]); + assert_pages(&[2]); }); } @@ -279,7 +279,7 @@ fn service_queues_low_weight_defensive() { assert!(MessageQueue::do_integrity_test().is_err()); MessageQueue::enqueue_message(msg("weight=0"), Here); - MessageQueue::service_queues(104.into_weight()); + MessageQueue::service_queues_impl(104.into_weight(), ServiceQueuesContext::OnInitialize); }); } @@ -313,7 +313,7 @@ fn reap_page_permanent_overweight_works() { // Create 10 pages more than the stale limit. let n = (MaxStale::get() + 10) as usize; for _ in 0..n { - MessageQueue::enqueue_message(msg("weight=2"), Here); + MessageQueue::enqueue_message(msg("weight=200 datadatadata"), Here); } assert_eq!(Pages::::iter().count(), n); assert_eq!(MessageQueue::footprint(Here).pages, n as u32); @@ -334,7 +334,7 @@ fn reap_page_permanent_overweight_works() { break } assert_ok!(MessageQueue::do_reap_page(&Here, i)); - assert_eq!(QueueChanges::take(), vec![(Here, b.message_count - 1, b.size - 8)]); + assert_eq!(QueueChanges::take(), vec![(Here, b.message_count - 1, b.size - 23)]); } // Cannot reap any more pages. @@ -353,20 +353,20 @@ fn reaping_overweight_fails_properly() { build_and_execute::(|| { // page 0 - MessageQueue::enqueue_message(msg("weight=4"), Here); + MessageQueue::enqueue_message(msg("weight=200 datadata"), Here); MessageQueue::enqueue_message(msg("a"), Here); // page 1 - MessageQueue::enqueue_message(msg("weight=4"), Here); + MessageQueue::enqueue_message(msg("weight=200 datadata"), Here); MessageQueue::enqueue_message(msg("b"), Here); // page 2 - MessageQueue::enqueue_message(msg("weight=4"), Here); + MessageQueue::enqueue_message(msg("weight=200 datadata"), Here); MessageQueue::enqueue_message(msg("c"), Here); // page 3 - MessageQueue::enqueue_message(msg("bigbig 1"), Here); + MessageQueue::enqueue_message(msg("bigbig 1 datadata"), Here); // page 4 - MessageQueue::enqueue_message(msg("bigbig 2"), Here); + MessageQueue::enqueue_message(msg("bigbig 2 datadata"), Here); // page 5 - MessageQueue::enqueue_message(msg("bigbig 3"), Here); + MessageQueue::enqueue_message(msg("bigbig 3 datadata"), Here); // Double-check that exactly these pages exist. assert_pages(&[0, 1, 2, 3, 4, 5]); @@ -385,7 +385,7 @@ fn reaping_overweight_fails_properly() { // 3 stale now: can take something 4 pages in history. assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); - assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 1"), Here)]); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 1 datadata"), Here)]); // Nothing reapable yet, because we haven't hit the stale limit. for (o, i, _) in Pages::::iter() { @@ -394,7 +394,7 @@ fn reaping_overweight_fails_properly() { assert_pages(&[0, 1, 2, 4, 5]); assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); - assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 2"), Here)]); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 2 datadata"), Here)]); assert_pages(&[0, 1, 2, 5]); // First is now reapable as it is too far behind the first ready page (5). @@ -406,7 +406,7 @@ fn reaping_overweight_fails_properly() { assert_pages(&[1, 2, 5]); assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); - assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 3"), Here)]); + assert_eq!(MessagesProcessed::take(), vec![(vmsg("bigbig 3 datadata"), Here)]); assert_noop!(MessageQueue::do_reap_page(&Here, 0), Error::::NoPage); assert_noop!(MessageQueue::do_reap_page(&Here, 3), Error::::NoPage); @@ -1062,29 +1062,29 @@ fn footprint_on_swept_works() { fn footprint_num_pages_works() { use MessageOrigin::*; build_and_execute::(|| { - MessageQueue::enqueue_message(msg("weight=2"), Here); - MessageQueue::enqueue_message(msg("weight=3"), Here); + MessageQueue::enqueue_message(msg("weight=200"), Here); + MessageQueue::enqueue_message(msg("weight=300"), Here); - assert_eq!(MessageQueue::footprint(Here), fp(2, 2, 2, 16)); + assert_eq!(MessageQueue::footprint(Here), fp(1, 1, 2, 20)); // Mark the messages as overweight. assert_eq!(MessageQueue::service_queues(1.into_weight()), 0.into_weight()); assert_eq!(System::events().len(), 2); // `ready_pages` decreases but `page` count does not. - assert_eq!(MessageQueue::footprint(Here), fp(2, 0, 2, 16)); + assert_eq!(MessageQueue::footprint(Here), fp(1, 0, 2, 20)); // Now execute the second message. assert_eq!( - ::execute_overweight(3.into_weight(), (Here, 1, 0)) + ::execute_overweight(300.into_weight(), (Here, 0, 1)) .unwrap(), - 3.into_weight() + 300.into_weight() ); - assert_eq!(MessageQueue::footprint(Here), fp(1, 0, 1, 8)); + assert_eq!(MessageQueue::footprint(Here), fp(1, 0, 1, 10)); // And the first one: assert_eq!( - ::execute_overweight(2.into_weight(), (Here, 0, 0)) + ::execute_overweight(200.into_weight(), (Here, 0, 0)) .unwrap(), - 2.into_weight() + 200.into_weight() ); assert_eq!(MessageQueue::footprint(Here), Default::default()); assert_eq!(MessageQueue::footprint(Here), fp(0, 0, 0, 0)); @@ -1104,7 +1104,7 @@ fn execute_overweight_works() { // Enqueue a message let origin = MessageOrigin::Here; - MessageQueue::enqueue_message(msg("weight=6"), origin); + MessageQueue::enqueue_message(msg("weight=200"), origin); // Load the current book let book = BookStateFor::::get(origin); assert_eq!(book.message_count, 1); @@ -1112,10 +1112,10 @@ fn execute_overweight_works() { // Mark the message as permanently overweight. assert_eq!(MessageQueue::service_queues(4.into_weight()), 4.into_weight()); - assert_eq!(QueueChanges::take(), vec![(origin, 1, 8)]); + assert_eq!(QueueChanges::take(), vec![(origin, 1, 10)]); assert_last_event::( Event::OverweightEnqueued { - id: blake2_256(b"weight=6"), + id: blake2_256(b"weight=200"), origin: MessageOrigin::Here, message_index: 0, page_index: 0, @@ -1132,9 +1132,9 @@ fn execute_overweight_works() { assert_eq!(Pages::::iter().count(), 1); assert!(QueueChanges::take().is_empty()); let consumed = - ::execute_overweight(7.into_weight(), (origin, 0, 0)) + ::execute_overweight(200.into_weight(), (origin, 0, 0)) .unwrap(); - assert_eq!(consumed, 6.into_weight()); + assert_eq!(consumed, 200.into_weight()); assert_eq!(QueueChanges::take(), vec![(origin, 0, 0)]); // There is no message left in the book. let book = BookStateFor::::get(origin); @@ -1162,7 +1162,7 @@ fn permanently_overweight_book_unknits() { set_weight("service_queue_base", 1.into_weight()); set_weight("service_page_base_completion", 1.into_weight()); - MessageQueue::enqueue_messages([msg("weight=9")].into_iter(), Here); + MessageQueue::enqueue_messages([msg("weight=200")].into_iter(), Here); // It is the only ready book. assert_ring(&[Here]); @@ -1170,7 +1170,7 @@ fn permanently_overweight_book_unknits() { assert_eq!(MessageQueue::service_queues(8.into_weight()), 4.into_weight()); assert_last_event::( Event::OverweightEnqueued { - id: blake2_256(b"weight=9"), + id: blake2_256(b"weight=200"), origin: Here, message_index: 0, page_index: 0, @@ -1201,19 +1201,19 @@ fn permanently_overweight_book_unknits_multiple() { set_weight("service_page_base_completion", 1.into_weight()); MessageQueue::enqueue_messages( - [msg("weight=1"), msg("weight=9"), msg("weight=9")].into_iter(), + [msg("weight=1"), msg("weight=200"), msg("weight=200")].into_iter(), Here, ); assert_ring(&[Here]); // Process the first message. assert_eq!(MessageQueue::service_queues(4.into_weight()), 4.into_weight()); - assert_eq!(num_overweight_enqueued_events(), 0); + assert_eq!(num_overweight_enqueued_events(), 1); assert_eq!(MessagesProcessed::take().len(), 1); // Book is still ready since it was not marked as overweight yet. assert_ring(&[Here]); - assert_eq!(MessageQueue::service_queues(8.into_weight()), 5.into_weight()); + assert_eq!(MessageQueue::service_queues(8.into_weight()), 4.into_weight()); assert_eq!(num_overweight_enqueued_events(), 2); assert_eq!(MessagesProcessed::take().len(), 0); // Now it is overweight. @@ -1566,12 +1566,12 @@ fn service_queues_suspend_works() { fn execute_overweight_respects_suspension() { build_and_execute::(|| { let origin = MessageOrigin::Here; - MessageQueue::enqueue_message(msg("weight=5"), origin); + MessageQueue::enqueue_message(msg("weight=200"), origin); // Mark the message as permanently overweight. MessageQueue::service_queues(4.into_weight()); assert_last_event::( Event::OverweightEnqueued { - id: blake2_256(b"weight=5"), + id: blake2_256(b"weight=200"), origin, message_index: 0, page_index: 0, @@ -1598,9 +1598,9 @@ fn execute_overweight_respects_suspension() { assert_last_event::( Event::Processed { - id: blake2_256(b"weight=5").into(), + id: blake2_256(b"weight=200").into(), origin, - weight_used: 5.into_weight(), + weight_used: 200.into_weight(), success: true, } .into(), @@ -1768,7 +1768,7 @@ fn recursive_overweight_while_service_is_forbidden() { // Check that the message was permanently overweight. assert_last_event::( Event::OverweightEnqueued { - id: blake2_256(b"weight=10"), + id: blake2_256(b"weight=200"), origin: There, message_index: 0, page_index: 0, @@ -1786,13 +1786,13 @@ fn recursive_overweight_while_service_is_forbidden() { Ok(()) })); - MessageQueue::enqueue_message(msg("weight=10"), There); + MessageQueue::enqueue_message(msg("weight=200"), There); MessageQueue::enqueue_message(msg("callback=0"), Here); // Mark it as permanently overweight. MessageQueue::service_queues(5.into_weight()); assert_ok!(::execute_overweight( - 10.into_weight(), + 200.into_weight(), (There, 0, 0) )); }); @@ -1812,7 +1812,7 @@ fn recursive_reap_page_is_forbidden() { // Create 10 pages more than the stale limit. let n = (MaxStale::get() + 10) as usize; for _ in 0..n { - MessageQueue::enqueue_message(msg("weight=2"), Here); + MessageQueue::enqueue_message(msg("weight=200"), Here); } // Mark all pages as stale since their message is permanently overweight. @@ -1886,6 +1886,11 @@ fn process_enqueued_on_idle_requires_enough_weight() { // Not enough weight to process on idle. Pallet::::on_idle(1, Weight::from_parts(0, 0)); assert_eq!(MessagesProcessed::take(), vec![]); + + assert!(!System::events().into_iter().any(|e| matches!( + e.event, + RuntimeEvent::MessageQueue(Event::::OverweightEnqueued { .. }) + ))); }) } @@ -1923,12 +1928,12 @@ fn execute_overweight_keeps_stack_ov_message() { // We need to create a mocked message that first reports insufficient weight, and then // `StackLimitReached`: IgnoreStackOvError::set(true); - MessageQueue::enqueue_message(msg("stacklimitreached"), Here); + MessageQueue::enqueue_message(msg("weight=200 stacklimitreached"), Here); MessageQueue::service_queues(0.into_weight()); assert_last_event::( Event::OverweightEnqueued { - id: blake2_256(b"stacklimitreached"), + id: blake2_256(b"weight=200 stacklimitreached"), origin: MessageOrigin::Here, message_index: 0, page_index: 0, @@ -1952,7 +1957,7 @@ fn execute_overweight_keeps_stack_ov_message() { ); assert_last_event::( Event::ProcessingFailed { - id: blake2_256(b"stacklimitreached").into(), + id: blake2_256(b"weight=200 stacklimitreached").into(), origin: MessageOrigin::Here, error: ProcessMessageError::StackLimitReached, } @@ -1964,16 +1969,16 @@ fn execute_overweight_keeps_stack_ov_message() { // Now let's process it normally: IgnoreStackOvError::set(true); assert_eq!( - ::execute_overweight(1.into_weight(), (Here, 0, 0)) + ::execute_overweight(200.into_weight(), (Here, 0, 0)) .unwrap(), - 1.into_weight() + 200.into_weight() ); assert_last_event::( Event::Processed { - id: blake2_256(b"stacklimitreached").into(), + id: blake2_256(b"weight=200 stacklimitreached").into(), origin: MessageOrigin::Here, - weight_used: 1.into_weight(), + weight_used: 200.into_weight(), success: true, } .into(), 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 10d90bba0911..bca2c3ffb198 100644 --- a/substrate/frame/metadata-hash-extension/Cargo.toml +++ b/substrate/frame/metadata-hash-extension/Cargo.toml @@ -17,6 +17,7 @@ frame-support = { workspace = true } frame-system = { workspace = true } log = { workspace = true } docify = { workspace = true } +const-hex = { workspace = true } [dev-dependencies] substrate-wasm-builder = { features = ["metadata-hash"], workspace = true, default-features = true } @@ -31,6 +32,7 @@ sp-tracing = { workspace = true, default-features = true } default = ["std"] std = [ "codec/std", + "const-hex/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/substrate/frame/metadata-hash-extension/src/lib.rs b/substrate/frame/metadata-hash-extension/src/lib.rs index d09acbfb3df2..0b45f5a7e515 100644 --- a/substrate/frame/metadata-hash-extension/src/lib.rs +++ b/substrate/frame/metadata-hash-extension/src/lib.rs @@ -17,14 +17,14 @@ #![cfg_attr(not(feature = "std"), no_std)] -//! The [`CheckMetadataHash`] signed extension. +//! The [`CheckMetadataHash`] transaction extension. //! //! The extension for optionally checking the metadata hash. For information how it works and what //! it does exactly, see the docs of [`CheckMetadataHash`]. //! //! # Integration //! -//! As any signed extension you will need to add it to your runtime signed extensions: +//! As any transaction extension you will need to add it to your runtime transaction extensions: #![doc = docify::embed!("src/tests.rs", add_metadata_hash_extension)] //! As the extension requires the `RUNTIME_METADATA_HASH` environment variable to be present at //! compile time, it requires a little bit more setup. To have this environment variable available @@ -39,11 +39,12 @@ extern crate alloc; extern crate self as frame_metadata_hash_extension; use codec::{Decode, Encode}; -use frame_support::DebugNoBound; +use frame_support::{pallet_prelude::Weight, DebugNoBound}; use frame_system::Config; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::TransactionExtension, transaction_validity::{TransactionValidityError, UnknownTransaction}, }; @@ -67,12 +68,24 @@ enum MetadataHash { Custom([u8; 32]), } +const RUNTIME_METADATA: Option<[u8; 32]> = if let Some(hex) = option_env!("RUNTIME_METADATA_HASH") { + match const_hex::const_decode_to_array(hex.as_bytes()) { + Ok(hex) => Some(hex), + Err(_) => panic!( + "Invalid RUNTIME_METADATA_HASH environment variable: it must be a 32 \ + bytes value in hexadecimal: e.g. 0x123ABCabd...123ABCabc. Upper case or lower case, \ + 0x prefix is optional." + ), + } +} else { + None +}; + impl MetadataHash { /// Returns the metadata hash. fn hash(&self) -> Option<[u8; 32]> { match self { - Self::FetchFromEnv => - option_env!("RUNTIME_METADATA_HASH").map(array_bytes::hex2array_unchecked), + Self::FetchFromEnv => RUNTIME_METADATA, Self::Custom(hash) => Some(*hash), } } @@ -85,15 +98,15 @@ impl MetadataHash { /// This metadata hash should give users the confidence that what they build with an online wallet /// is the same they are signing with their offline wallet and then applying on chain. To ensure /// that the online wallet is not tricking the offline wallet into decoding and showing an incorrect -/// extrinsic, the offline wallet will include the metadata hash into the additional signed data and +/// extrinsic, the offline wallet will include the metadata hash into the extension implicit and /// the runtime will then do the same. If the metadata hash doesn't match, the signature /// verification will fail and thus, the transaction will be rejected. The RFC contains more details /// on how it works. /// /// The extension adds one byte (the `mode`) to the size of the extrinsic. This one byte is -/// controlling if the metadata hash should be added to the signed data or not. Mode `0` means that -/// the metadata hash is not added and thus, `None` is added to the signed data. Mode `1` means that -/// the metadata hash is added and thus, `Some(metadata_hash)` is added to the signed data. Further +/// controlling if the metadata hash should be added to the implicit or not. Mode `0` means that +/// the metadata hash is not added and thus, `None` is added to the implicit. Mode `1` means that +/// the metadata hash is added and thus, `Some(metadata_hash)` is added to the implicit. Further /// values of `mode` are reserved for future changes. /// /// The metadata hash is read from the environment variable `RUNTIME_METADATA_HASH`. This @@ -110,7 +123,7 @@ pub struct CheckMetadataHash { } impl CheckMetadataHash { - /// Creates new `SignedExtension` to check metadata hash. + /// Creates new `TransactionExtension` to check metadata hash. pub fn new(enable: bool) -> Self { Self { _phantom: core::marker::PhantomData, @@ -131,14 +144,10 @@ impl CheckMetadataHash { } } -impl SignedExtension for CheckMetadataHash { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = Option<[u8; 32]>; - type Pre = (); +impl TransactionExtension for CheckMetadataHash { const IDENTIFIER: &'static str = "CheckMetadataHash"; - - fn additional_signed(&self) -> Result { + type Implicit = Option<[u8; 32]>; + fn implicit(&self) -> Result { let signed = match self.mode { Mode::Disabled => None, Mode::Enabled => match self.metadata_hash.hash() { @@ -149,20 +158,20 @@ impl SignedExtension for CheckMetadataHash { log::debug!( target: "runtime::metadata-hash", - "CheckMetadataHash::additional_signed => {:?}", + "CheckMetadataHash::implicit => {:?}", signed.as_ref().map(|h| array_bytes::bytes2hex("0x", h)), ); Ok(signed) } + type Val = (); + type Pre = (); - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + fn weight(&self, _: &T::RuntimeCall) -> Weight { + // The weight is the weight of implicit, it consists of a few match operation, it is + // negligible. + Weight::zero() } + + impl_tx_ext_default!(T::RuntimeCall; validate prepare); } diff --git a/substrate/frame/metadata-hash-extension/src/tests.rs b/substrate/frame/metadata-hash-extension/src/tests.rs index f13eecfd94bf..11a3345ee15c 100644 --- a/substrate/frame/metadata-hash-extension/src/tests.rs +++ b/substrate/frame/metadata-hash-extension/src/tests.rs @@ -25,7 +25,7 @@ use frame_support::{ use merkleized_metadata::{generate_metadata_digest, ExtraInfo}; use sp_api::{Metadata, ProvideRuntimeApi}; use sp_runtime::{ - traits::{Extrinsic as _, SignedExtension}, + traits::{ExtrinsicLike, TransactionExtension}, transaction_validity::{TransactionSource, UnknownTransaction}, }; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; @@ -51,7 +51,7 @@ impl frame_system::Config for Test { #[test] fn rejects_when_no_metadata_hash_was_passed() { let ext = CheckMetadataHash::::decode(&mut &1u8.encode()[..]).unwrap(); - assert_eq!(Err(UnknownTransaction::CannotLookup.into()), ext.additional_signed()); + assert_eq!(Err(UnknownTransaction::CannotLookup.into()), ext.implicit()); } #[test] @@ -92,7 +92,7 @@ fn ensure_check_metadata_works_on_real_extrinsics() { .metadata_hash(generate_metadata_hash(metadata)) .build(); // Ensure that the transaction is signed. - assert!(valid_transaction.is_signed().unwrap()); + assert!(!valid_transaction.is_bare()); runtime_api .validate_transaction(best_hash, TransactionSource::External, valid_transaction, best_hash) @@ -104,7 +104,7 @@ fn ensure_check_metadata_works_on_real_extrinsics() { .metadata_hash([10u8; 32]) .build(); // Ensure that the transaction is signed. - assert!(invalid_transaction.is_signed().unwrap()); + assert!(!invalid_transaction.is_bare()); assert_eq!( TransactionValidityError::from(InvalidTransaction::BadProof), @@ -132,8 +132,8 @@ mod docs { } } - /// The `SignedExtension` to the basic transaction logic. - pub type SignedExtra = ( + /// The `TransactionExtension` to the basic transaction logic. + pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -153,7 +153,7 @@ mod docs { /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - sp_runtime::generic::UncheckedExtrinsic; + sp_runtime::generic::UncheckedExtrinsic; } // Put here to not have it in the docs as well. diff --git a/substrate/frame/migrations/src/benchmarking.rs b/substrate/frame/migrations/src/benchmarking.rs index 8ad1fa50d149..c076d40bb05c 100644 --- a/substrate/frame/migrations/src/benchmarking.rs +++ b/substrate/frame/migrations/src/benchmarking.rs @@ -158,7 +158,7 @@ mod benches { fn on_init_loop() { T::Migrations::set_fail_after(0); // Should not be called anyway. System::::set_block_number(1u32.into()); - Pallet::::on_runtime_upgrade(); + as Hooks>>::on_runtime_upgrade(); #[block] { 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/mixnet/src/lib.rs b/substrate/frame/mixnet/src/lib.rs index c0505a4f0105..6579ed678ae7 100644 --- a/substrate/frame/mixnet/src/lib.rs +++ b/substrate/frame/mixnet/src/lib.rs @@ -31,7 +31,7 @@ use frame_support::{ BoundedVec, }; use frame_system::{ - offchain::{SendTransactionTypes, SubmitTransaction}, + offchain::{CreateInherent, SubmitTransaction}, pallet_prelude::BlockNumberFor, }; pub use pallet::*; @@ -178,7 +178,7 @@ pub mod pallet { pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config + SendTransactionTypes> { + pub trait Config: frame_system::Config + CreateInherent> { /// The maximum number of authorities per session. #[pallet::constant] type MaxAuthorities: Get; @@ -531,7 +531,8 @@ impl Pallet { return false }; let call = Call::register { registration, signature }; - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { + let xt = T::create_inherent(call.into()); + match SubmitTransaction::>::submit_transaction(xt) { Ok(()) => true, Err(()) => { log::debug!( diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index b24df856bcd7..c96be908faef 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -18,11 +18,7 @@ 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 } -sp-io = { workspace = true } -sp-runtime = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } # third party log = { workspace = true } @@ -34,25 +30,15 @@ pallet-balances = { workspace = true, default-features = true } default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", + "frame/std", "log/std", - "pallet-balances/std", "scale-info/std", - "sp-io/std", - "sp-runtime/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", + "frame/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", ] 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/multisig/src/benchmarking.rs b/substrate/frame/multisig/src/benchmarking.rs index ebe19df5dc43..ccaa1ceab66e 100644 --- a/substrate/frame/multisig/src/benchmarking.rs +++ b/substrate/frame/multisig/src/benchmarking.rs @@ -20,9 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::{account, benchmarks}; -use frame_system::RawOrigin; -use sp_runtime::traits::Bounded; +use frame::benchmarking::prelude::*; use crate::Pallet as Multisig; @@ -47,48 +45,59 @@ fn setup_multi( Ok((signatories, Box::new(call))) } -benchmarks! { - as_multi_threshold_1 { - // Transaction Length - let z in 0 .. 10_000; +#[benchmarks] +mod benchmarks { + use super::*; + + /// `z`: Transaction Length + #[benchmark] + fn as_multi_threshold_1(z: Linear<0, 10_000>) -> Result<(), BenchmarkError> { let max_signatories = T::MaxSignatories::get().into(); let (mut signatories, _) = setup_multi::(max_signatories, z)?; - let call: ::RuntimeCall = frame_system::Call::::remark { - remark: vec![0; z as usize] - }.into(); - let call_hash = call.using_encoded(blake2_256); - let multi_account_id = Multisig::::multi_account_id(&signatories, 1); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller.clone()), signatories, Box::new(call)) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), signatories, Box::new(call)); + // If the benchmark resolves, then the call was dispatched successfully. + Ok(()) } - as_multi_create { - // Signatories, need at least 2 total people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length - let z in 0 .. 10_000; + /// `z`: Transaction Length + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn as_multi_create( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero()) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero()); + assert!(Multisigs::::contains_key(multi_account_id, call_hash)); + + Ok(()) } - as_multi_approve { - // Signatories, need at least 3 people (so we don't complete the multisig) - let s in 3 .. T::MaxSignatories::get(); - // Transaction Length - let z in 0 .. 10_000; + /// `z`: Transaction Length + /// `s`: Signatories, need at least 3 people (so we don't complete the multisig) + #[benchmark] + fn as_multi_approve( + s: Linear<3, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); @@ -97,22 +106,43 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; + Multisig::::as_multi( + RawOrigin::Signed(caller).into(), + s as u16, + signatories, + None, + call.clone(), + Weight::zero(), + )?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::zero()) - verify { - let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + as_multi( + RawOrigin::Signed(caller2), + s as u16, + signatories2, + Some(timepoint), + call, + Weight::zero(), + ); + + let multisig = + Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); + + Ok(()) } - as_multi_complete { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length - let z in 0 .. 10_000; + /// `z`: Transaction Length + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn as_multi_complete( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); @@ -121,47 +151,87 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; + Multisig::::as_multi( + RawOrigin::Signed(caller).into(), + s as u16, + signatories, + None, + call.clone(), + Weight::zero(), + )?; // Everyone except the first person approves - for i in 1 .. s - 1 { + for i in 1..s - 1 { let mut signatories_loop = signatories2.clone(); let caller_loop = signatories_loop.remove(i as usize); let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), Weight::zero())?; + Multisig::::as_multi( + o, + s as u16, + signatories_loop, + Some(timepoint), + call.clone(), + Weight::zero(), + )?; } let caller2 = signatories2.remove(0); assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::MAX) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + as_multi( + RawOrigin::Signed(caller2), + s as u16, + signatories2, + Some(timepoint), + call, + Weight::MAX, + ); + assert!(!Multisigs::::contains_key(&multi_account_id, call_hash)); + + Ok(()) } - approve_as_multi_create { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length, not a component - let z = 10_000; + /// `z`: Transaction Length, not a component + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn approve_as_multi_create( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; let call_hash = call.using_encoded(blake2_256); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); + add_to_whitelist(caller_key.into()); + // Create the multi - }: approve_as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call_hash, Weight::zero()) - verify { + #[extrinsic_call] + approve_as_multi( + RawOrigin::Signed(caller), + s as u16, + signatories, + None, + call_hash, + Weight::zero(), + ); + assert!(Multisigs::::contains_key(multi_account_id, call_hash)); + + Ok(()) } - approve_as_multi_approve { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length, not a component - let z = 10_000; + /// `z`: Transaction Length, not a component + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn approve_as_multi_approve( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let mut signatories2 = signatories.clone(); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); @@ -176,23 +246,37 @@ benchmarks! { signatories, None, call, - Weight::zero() + Weight::zero(), )?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: approve_as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call_hash, Weight::zero()) - verify { - let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + approve_as_multi( + RawOrigin::Signed(caller2), + s as u16, + signatories2, + Some(timepoint), + call_hash, + Weight::zero(), + ); + + let multisig = + Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); + + Ok(()) } - cancel_as_multi { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length, not a component - let z = 10_000; + /// `z`: Transaction Length, not a component + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn cancel_as_multi( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -204,10 +288,14 @@ benchmarks! { assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash); + assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); + + Ok(()) } impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/substrate/frame/multisig/src/lib.rs b/substrate/frame/multisig/src/lib.rs index 51c36773bdad..4a30b5c119b9 100644 --- a/substrate/frame/multisig/src/lib.rs +++ b/substrate/frame/multisig/src/lib.rs @@ -49,28 +49,15 @@ mod tests; pub mod weights; extern crate alloc; - use alloc::{boxed::Box, vec, vec::Vec}; -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::{ - DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, - PostDispatchInfo, - }, - ensure, - traits::{Currency, Get, ReservableCurrency}, - weights::Weight, - BoundedVec, -}; -use frame_system::{self as system, pallet_prelude::BlockNumberFor, RawOrigin}; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - traits::{Dispatchable, TrailingZeroInput, Zero}, - DispatchError, RuntimeDebug, +use frame::{ + prelude::*, + traits::{Currency, ReservableCurrency}, }; +use frame_system::RawOrigin; pub use weights::WeightInfo; +/// Re-export all pallet items. pub use pallet::*; /// The log target of this pallet. @@ -127,11 +114,9 @@ enum CallOrHash { Hash([u8; 32]), } -#[frame_support::pallet] +#[frame::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { @@ -167,7 +152,7 @@ pub mod pallet { type MaxSignatories: Get; /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; + type WeightInfo: weights::WeightInfo; } /// The in-code storage version. @@ -273,7 +258,7 @@ pub mod pallet { T::WeightInfo::as_multi_threshold_1(call.using_encoded(|c| c.len() as u32)) // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(dispatch_info.weight), + .saturating_add(dispatch_info.call_weight), dispatch_info.class, ) })] @@ -554,7 +539,7 @@ impl Pallet { if let Some(call) = maybe_call.filter(|_| approvals >= threshold) { // verify weight ensure!( - call.get_dispatch_info().weight.all_lte(max_weight), + call.get_dispatch_info().call_weight.all_lte(max_weight), Error::::MaxWeightTooLow ); @@ -641,8 +626,8 @@ impl Pallet { /// The current `Timepoint`. pub fn timepoint() -> Timepoint> { Timepoint { - height: >::block_number(), - index: >::extrinsic_index().unwrap_or_default(), + height: >::block_number(), + index: >::extrinsic_index().unwrap_or_default(), } } diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs index e6402600d0d3..8d6e77813673 100644 --- a/substrate/frame/multisig/src/migrations.rs +++ b/substrate/frame/multisig/src/migrations.rs @@ -17,21 +17,15 @@ // Migrations for Multisig Pallet -use super::*; -use frame_support::{ - traits::{GetStorageVersion, OnRuntimeUpgrade, WrapperKeepOpaque}, - Identity, -}; - -#[cfg(feature = "try-runtime")] -use frame_support::ensure; +use crate::*; +use frame::prelude::*; pub mod v1 { use super::*; - type OpaqueCall = WrapperKeepOpaque<::RuntimeCall>; + type OpaqueCall = frame::traits::WrapperKeepOpaque<::RuntimeCall>; - #[frame_support::storage_alias] + #[frame::storage_alias] type Calls = StorageMap< Pallet, Identity, @@ -42,15 +36,14 @@ pub mod v1 { pub struct MigrateToV1(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + fn pre_upgrade() -> Result, frame::try_runtime::TryRuntimeError> { log!(info, "Number of calls to refund and delete: {}", Calls::::iter().count()); Ok(Vec::new()) } fn on_runtime_upgrade() -> Weight { - use sp_runtime::Saturating; - + use frame::traits::ReservableCurrency as _; let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); @@ -76,7 +69,7 @@ pub mod v1 { } #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + fn post_upgrade(_state: Vec) -> Result<(), frame::try_runtime::TryRuntimeError> { ensure!( Calls::::iter().count() == 0, "there are some dangling calls that need to be destroyed and refunded" diff --git a/substrate/frame/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs index cfdd33f7dfcc..c5a98845270c 100644 --- a/substrate/frame/multisig/src/tests.rs +++ b/substrate/frame/multisig/src/tests.rs @@ -20,18 +20,13 @@ #![cfg(test)] use super::*; - use crate as pallet_multisig; -use frame_support::{ - assert_noop, assert_ok, derive_impl, - traits::{ConstU32, ConstU64, Contains}, -}; -use sp_runtime::{BuildStorage, TokenError}; +use frame::{prelude::*, runtime::prelude::*, testing_prelude::*}; type Block = frame_system::mocking::MockBlockU32; -frame_support::construct_runtime!( - pub enum Test { +construct_runtime!( + pub struct Test { System: frame_system, Balances: pallet_balances, Multisig: pallet_multisig, @@ -75,14 +70,14 @@ impl Config for Test { use pallet_balances::Call as BalancesCall; -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestState { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 2)], } .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); + let mut ext = TestState::new(t); ext.execute_with(|| System::set_block_number(1)); ext } @@ -104,7 +99,7 @@ fn multisig_deposit_is_taken_and_returned() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, @@ -225,7 +220,7 @@ fn multisig_2_of_3_works() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( RuntimeOrigin::signed(1), @@ -258,7 +253,7 @@ fn multisig_3_of_3_works() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( RuntimeOrigin::signed(1), @@ -328,7 +323,7 @@ fn multisig_2_of_3_as_multi_works() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), 2, @@ -360,9 +355,9 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call1 = call_transfer(6, 10); - let call1_weight = call1.get_dispatch_info().weight; + let call1_weight = call1.get_dispatch_info().call_weight; let call2 = call_transfer(7, 5); - let call2_weight = call2.get_dispatch_info().weight; + let call2_weight = call2.get_dispatch_info().call_weight; assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), @@ -411,7 +406,7 @@ fn multisig_2_of_3_cannot_reissue_same_call() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 10); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let hash = blake2_256(&call.encode()); assert_ok!(Multisig::as_multi( RuntimeOrigin::signed(1), @@ -652,7 +647,7 @@ fn multisig_handles_no_preimage_after_all_approve() { assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( RuntimeOrigin::signed(1), diff --git a/substrate/frame/multisig/src/weights.rs b/substrate/frame/multisig/src/weights.rs index ac1c1b23b030..5c14922e0ef0 100644 --- a/substrate/frame/multisig/src/weights.rs +++ b/substrate/frame/multisig/src/weights.rs @@ -46,9 +46,8 @@ #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - +// TODO update this in frame-weight-template.hbs +use frame::weights_prelude::*; /// Weight functions needed for `pallet_multisig`. pub trait WeightInfo { fn as_multi_threshold_1(z: u32, ) -> Weight; @@ -295,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/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/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/src/types.rs b/substrate/frame/nfts/src/types.rs index 60d7c639c88c..d67fb404ea79 100644 --- a/substrate/frame/nfts/src/types.rs +++ b/substrate/frame/nfts/src/types.rs @@ -31,49 +31,48 @@ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter}; /// A type alias for handling balance deposits. -pub(super) type DepositBalanceOf = +pub type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; /// A type alias representing the details of a collection. -pub(super) type CollectionDetailsFor = +pub type CollectionDetailsFor = CollectionDetails<::AccountId, DepositBalanceOf>; /// A type alias for keeping track of approvals used by a single item. -pub(super) type ApprovalsOf = BoundedBTreeMap< +pub type ApprovalsOf = BoundedBTreeMap< ::AccountId, Option>, >::ApprovalsLimit, >; /// A type alias for keeping track of approvals for an item's attributes. -pub(super) type ItemAttributesApprovals = +pub type ItemAttributesApprovals = BoundedBTreeSet<::AccountId, >::ItemAttributesApprovalsLimit>; /// A type that holds the deposit for a single item. -pub(super) type ItemDepositOf = - ItemDeposit, ::AccountId>; +pub type ItemDepositOf = ItemDeposit, ::AccountId>; /// A type that holds the deposit amount for an item's attribute. -pub(super) type AttributeDepositOf = +pub type AttributeDepositOf = AttributeDeposit, ::AccountId>; /// A type that holds the deposit amount for an item's metadata. -pub(super) type ItemMetadataDepositOf = +pub type ItemMetadataDepositOf = ItemMetadataDeposit, ::AccountId>; /// A type that holds the details of a single item. -pub(super) type ItemDetailsFor = +pub type ItemDetailsFor = ItemDetails<::AccountId, ItemDepositOf, ApprovalsOf>; /// A type alias for an accounts balance. -pub(super) type BalanceOf = +pub type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; /// A type alias to represent the price of an item. -pub(super) type ItemPrice = BalanceOf; +pub type ItemPrice = BalanceOf; /// A type alias for the tips held by a single item. -pub(super) type ItemTipOf = ItemTip< +pub type ItemTipOf = ItemTip< >::CollectionId, >::ItemId, ::AccountId, BalanceOf, >; /// A type alias for the settings configuration of a collection. -pub(super) type CollectionConfigFor = +pub type CollectionConfigFor = CollectionConfig, BlockNumberFor, >::CollectionId>; /// A type alias for the pre-signed minting configuration for a specified collection. -pub(super) type PreSignedMintOf = PreSignedMint< +pub type PreSignedMintOf = PreSignedMint< >::CollectionId, >::ItemId, ::AccountId, @@ -81,7 +80,7 @@ pub(super) type PreSignedMintOf = PreSignedMint< BalanceOf, >; /// A type alias for the pre-signed minting configuration on the attribute level of an item. -pub(super) type PreSignedAttributesOf = PreSignedAttributes< +pub type PreSignedAttributesOf = PreSignedAttributes< >::CollectionId, >::ItemId, ::AccountId, @@ -92,18 +91,18 @@ pub(super) type PreSignedAttributesOf = PreSignedAttributes< #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { /// Collection's owner. - pub(super) owner: AccountId, + pub owner: AccountId, /// The total balance deposited by the owner for all the storage data associated with this /// collection. Used by `destroy`. - pub(super) owner_deposit: DepositBalance, + pub owner_deposit: DepositBalance, /// The total number of outstanding items of this collection. - pub(super) items: u32, + pub items: u32, /// The total number of outstanding item metadata of this collection. - pub(super) item_metadatas: u32, + pub item_metadatas: u32, /// The total number of outstanding item configs of this collection. - pub(super) item_configs: u32, + pub item_configs: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + pub attributes: u32, } /// Witness data for the destroy transactions. @@ -143,21 +142,21 @@ pub struct MintWitness { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ItemDetails { /// The owner of this item. - pub(super) owner: AccountId, + pub owner: AccountId, /// The approved transferrer of this item, if one is set. - pub(super) approvals: Approvals, + pub approvals: Approvals, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub(super) deposit: Deposit, + pub deposit: Deposit, } /// Information about the reserved item deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemDeposit { /// A depositor account. - pub(super) account: AccountId, + pub account: AccountId, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + pub amount: DepositBalance, } /// Information about the collection's metadata. @@ -168,11 +167,11 @@ pub struct CollectionMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. - pub(super) deposit: Deposit, + pub deposit: Deposit, /// General information concerning this collection. Limited in length by `StringLimit`. This /// will generally be either a JSON dump or the hash of some JSON which can be found on a /// hash-addressable global publication system such as IPFS. - pub(super) data: BoundedVec, + pub data: BoundedVec, } /// Information about the item's metadata. @@ -182,11 +181,11 @@ pub struct ItemMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. - pub(super) deposit: Deposit, + pub deposit: Deposit, /// General information concerning this item. Limited in length by `StringLimit`. This will - /// generally be either a JSON dump or the hash of some JSON which can be found on a + /// generally be either a JSON dump or the hash of some JSON which can be found on /// hash-addressable global publication system such as IPFS. - pub(super) data: BoundedVec, + pub data: BoundedVec, } /// Information about the tip. @@ -206,31 +205,31 @@ pub struct ItemTip { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct PendingSwap { /// The collection that contains the item that the user wants to receive. - pub(super) desired_collection: CollectionId, + pub desired_collection: CollectionId, /// The item the user wants to receive. - pub(super) desired_item: Option, + pub desired_item: Option, /// A price for the desired `item` with the direction. - pub(super) price: Option, + pub price: Option, /// A deadline for the swap. - pub(super) deadline: Deadline, + pub deadline: Deadline, } /// Information about the reserved attribute deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct AttributeDeposit { /// A depositor account. - pub(super) account: Option, + pub account: Option, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + pub amount: DepositBalance, } /// Information about the reserved item's metadata deposit. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ItemMetadataDeposit { /// A depositor account, None means the deposit is collection's owner. - pub(super) account: Option, + pub account: Option, /// An amount that gets reserved. - pub(super) amount: DepositBalance, + pub amount: DepositBalance, } /// Specifies whether the tokens will be sent or received. 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/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/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index 2a4559425111..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, @@ -41,7 +41,7 @@ use sp_runtime::{ traits::{Bounded, StaticLookup, Zero}, Perbill, }; -use sp_staking::EraIndex; +use sp_staking::{EraIndex, StakingUnchecked}; // `frame_benchmarking::benchmarks!` macro needs this use pallet_nomination_pools::Call; @@ -131,6 +131,8 @@ fn migrate_to_transfer_stake(pool_id: PoolId) { ) .expect("member should have enough balance to transfer"); }); + + pallet_staking::Pallet::::migrate_to_direct_staker(&pool_acc); } fn vote_to_balance( @@ -268,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 @@ -289,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)), @@ -302,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 @@ -354,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); @@ -388,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!( @@ -427,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!( @@ -441,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!( @@ -471,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!( @@ -485,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()); @@ -517,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) @@ -542,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)); @@ -561,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(); @@ -606,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(); @@ -646,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()); @@ -657,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)); @@ -695,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 { @@ -717,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(); @@ -730,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); @@ -854,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::( @@ -907,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); @@ -959,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/runtime-api/src/lib.rs b/substrate/frame/nomination-pools/runtime-api/src/lib.rs index d81ad1dd4954..4138dd22d898 100644 --- a/substrate/frame/nomination-pools/runtime-api/src/lib.rs +++ b/substrate/frame/nomination-pools/runtime-api/src/lib.rs @@ -69,5 +69,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/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 272b3b60612b..f125919dabfa 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -460,6 +460,6 @@ impl< #[cfg(feature = "runtime-benchmarks")] fn remove_as_agent(pool: Pool) { - Delegation::migrate_to_direct_staker(pool.into()) + Delegation::force_kill_agent(pool.into()) } } diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 177c5da74d4f..201b0af1d608 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -4020,6 +4020,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/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 7fee2a0bdb23..40025cdbb3cd 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -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)); @@ -540,7 +540,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)); @@ -758,7 +758,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 +837,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)); @@ -914,7 +914,7 @@ 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 +1192,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 +1369,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/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/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index b16e5be653d1..573114de0742 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -20,7 +20,7 @@ use alloc::{vec, vec::Vec}; use frame_benchmarking::v1::{account, benchmarks}; -use frame_support::traits::{Currency, Get}; +use frame_support::traits::Get; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; use sp_runtime::{ @@ -77,8 +77,7 @@ where } type LookupSourceOf = <::Lookup as StaticLookup>::Source; -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; +type BalanceOf = ::CurrencyBalance; struct Offender { pub controller: T::AccountId, @@ -89,7 +88,7 @@ struct Offender { } fn bond_amount() -> BalanceOf { - T::Currency::minimum_balance().saturating_mul(10_000u32.into()) + pallet_staking::asset::existential_deposit::().saturating_mul(10_000u32.into()) } fn create_offender(n: u32, nominators: u32) -> Result, &'static str> { @@ -99,7 +98,7 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' let amount = bond_amount::(); // add twice as much balance to prevent the account from being killed. let free_amount = amount.saturating_mul(2u32.into()); - T::Currency::make_free_balance_be(&stash, free_amount); + pallet_staking::asset::set_stakeable_balance::(&stash, free_amount); Staking::::bond( RawOrigin::Signed(stash.clone()).into(), amount, @@ -116,7 +115,7 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' for i in 0..nominators { let nominator_stash: T::AccountId = account("nominator stash", n * MAX_NOMINATORS + i, SEED); - T::Currency::make_free_balance_be(&nominator_stash, free_amount); + pallet_staking::asset::set_stakeable_balance::(&nominator_stash, free_amount); Staking::::bond( RawOrigin::Signed(nominator_stash.clone()).into(), @@ -172,6 +171,14 @@ fn make_offenders( } benchmarks! { + where_clause { + where + ::RuntimeEvent: TryInto>, + ::RuntimeEvent: TryInto>, + ::RuntimeEvent: TryInto, + ::RuntimeEvent: TryInto>, + } + report_offence_grandpa { let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); @@ -196,17 +203,19 @@ benchmarks! { let _ = Offences::::report_offence(reporters, offence); } verify { - // make sure that all slashes have been applied #[cfg(test)] - assert_eq!( - System::::event_count(), 0 - + 1 // offence - + 3 // reporter (reward + endowment) - + 1 // offenders reported - + 3 // offenders slashed - + 1 // offenders chilled - + 3 * n // nominators slashed - ); + { + // 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); + } } report_offence_babe { @@ -233,17 +242,19 @@ benchmarks! { let _ = Offences::::report_offence(reporters, offence); } verify { - // make sure that all slashes have been applied #[cfg(test)] - assert_eq!( - System::::event_count(), 0 - + 1 // offence - + 3 // reporter (reward + endowment) - + 1 // offenders reported - + 3 // offenders slashed - + 1 // offenders chilled - + 3 * n // nominators slashed - ); + { + // 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); + } } 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 e243ad0e718e..efaec49a65b3 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -112,8 +112,6 @@ parameter_types! { pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); } -pub type Extrinsic = sp_runtime::testing::TestXt; - pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { type System = Test; @@ -157,12 +155,21 @@ impl pallet_offences::Config for Test { type OnOffenceHandler = Staking; } -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { - type Extrinsic = Extrinsic; - type OverarchingCall = RuntimeCall; + 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) + } } impl crate::Config for Test {} diff --git a/substrate/frame/offences/src/lib.rs b/substrate/frame/offences/src/lib.rs index ffea32a1f470..18f37c759a6a 100644 --- a/substrate/frame/offences/src/lib.rs +++ b/substrate/frame/offences/src/lib.rs @@ -73,7 +73,6 @@ pub mod pallet { /// The primary structure that holds all offence records keyed by report identifiers. #[pallet::storage] - #[pallet::getter(fn reports)] pub type Reports = StorageMap< _, Twox64Concat, @@ -152,6 +151,13 @@ where } impl Pallet { + /// Get the offence details from reports of given ID. + pub fn reports( + report_id: ReportIdOf, + ) -> Option> { + Reports::::get(report_id) + } + /// Compute the ID for the given report properties. /// /// The report id depends on the offence kind, time slot and the id of offender. diff --git a/substrate/frame/offences/src/tests.rs b/substrate/frame/offences/src/tests.rs index 4897b78f3e4d..ab72b51054d6 100644 --- a/substrate/frame/offences/src/tests.rs +++ b/substrate/frame/offences/src/tests.rs @@ -21,12 +21,34 @@ use super::*; use crate::mock::{ - new_test_ext, offence_reports, with_on_offence_fractions, Offence, Offences, RuntimeEvent, - System, KIND, + new_test_ext, offence_reports, with_on_offence_fractions, Offence, Offences, Runtime, + RuntimeEvent, System, KIND, }; use frame_system::{EventRecord, Phase}; +use sp_core::H256; use sp_runtime::Perbill; +#[test] +fn should_get_reports_with_storagemap_getter_and_function_getter() { + new_test_ext().execute_with(|| { + // given + let report_id: ReportIdOf = H256::from_low_u64_be(1); + let offence_details = OffenceDetails { offender: 1, reporters: vec![2, 3] }; + + Reports::::insert(report_id, offence_details.clone()); + + // when + let stored_offence_details = Offences::reports(report_id); + // then + assert_eq!(stored_offence_details, Some(offence_details.clone())); + + // when + let stored_offence_details = Reports::::get(report_id); + // then + assert_eq!(stored_offence_details, Some(offence_details.clone())); + }); +} + #[test] fn should_report_an_authority_and_trigger_on_offence() { new_test_ext().execute_with(|| { 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/src/weights.rs b/substrate/frame/preimage/src/weights.rs index 4e389e3a7340..edb2eed9c75a 100644 --- a/substrate/frame/preimage/src/weights.rs +++ b/substrate/frame/preimage/src/weights.rs @@ -18,9 +18,9 @@ //! 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-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,18 +76,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_981_000 picoseconds. + Weight::from_parts(52_228_000, 6012) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_392, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -100,12 +100,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: 15_835_000 picoseconds. + Weight::from_parts(16_429_000, 3556) + // Standard Error: 8 + .saturating_add(Weight::from_parts(2_647, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -118,12 +118,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_263_000 picoseconds. + Weight::from_parts(15_578_000, 3556) + // Standard Error: 7 + .saturating_add(Weight::from_parts(2_598, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -132,15 +132,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: 64_189_000 picoseconds. + Weight::from_parts(70_371_000, 3820) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -152,10 +152,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: 27_582_000 picoseconds. + Weight::from_parts(31_256_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -165,10 +165,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: 27_667_000 picoseconds. + Weight::from_parts(32_088_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -178,10 +178,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: 16_065_000 picoseconds. + Weight::from_parts(20_550_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -191,10 +191,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: 13_638_000 picoseconds. + Weight::from_parts(16_979_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -204,10 +204,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: 11_383_000 picoseconds. + Weight::from_parts(12_154_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -219,10 +219,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_832_000 picoseconds. + Weight::from_parts(30_716_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -232,10 +232,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_685_000 picoseconds. + Weight::from_parts(12_129_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -245,10 +245,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_394_000 picoseconds. + Weight::from_parts(10_951_000, 3556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -259,22 +259,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: 62_203_000 picoseconds. + Weight::from_parts(63_735_000, 6012) + // Standard Error: 59_589 + .saturating_add(Weight::from_parts(59_482_352, 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 +287,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_981_000 picoseconds. + Weight::from_parts(52_228_000, 6012) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_392, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -311,12 +311,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: 15_835_000 picoseconds. + Weight::from_parts(16_429_000, 3556) + // Standard Error: 8 + .saturating_add(Weight::from_parts(2_647, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -329,12 +329,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_263_000 picoseconds. + Weight::from_parts(15_578_000, 3556) + // Standard Error: 7 + .saturating_add(Weight::from_parts(2_598, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -343,15 +343,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: 64_189_000 picoseconds. + Weight::from_parts(70_371_000, 3820) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -363,10 +363,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: 27_582_000 picoseconds. + Weight::from_parts(31_256_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -376,10 +376,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: 27_667_000 picoseconds. + Weight::from_parts(32_088_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -389,10 +389,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: 16_065_000 picoseconds. + Weight::from_parts(20_550_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -402,10 +402,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: 13_638_000 picoseconds. + Weight::from_parts(16_979_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -415,10 +415,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: 11_383_000 picoseconds. + Weight::from_parts(12_154_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -430,10 +430,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_832_000 picoseconds. + Weight::from_parts(30_716_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -443,10 +443,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_685_000 picoseconds. + Weight::from_parts(12_129_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -456,10 +456,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_394_000 picoseconds. + Weight::from_parts(10_951_000, 3556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -470,21 +470,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: 62_203_000 picoseconds. + Weight::from_parts(63_735_000, 6012) + // Standard Error: 59_589 + .saturating_add(Weight::from_parts(59_482_352, 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 40c1c9750614..8897c66419c7 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -18,43 +18,26 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["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 } -sp-io = { workspace = true } -sp-runtime = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } pallet-utility = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } [features] default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "pallet-balances/std", - "pallet-utility/std", + "frame/std", "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", + "frame/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-utility/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", + "frame/try-runtime", "pallet-balances/try-runtime", "pallet-utility/try-runtime", - "sp-runtime/try-runtime", ] diff --git a/substrate/frame/proxy/src/benchmarking.rs b/substrate/frame/proxy/src/benchmarking.rs index 4081af49c243..eebb506bf374 100644 --- a/substrate/frame/proxy/src/benchmarking.rs +++ b/substrate/frame/proxy/src/benchmarking.rs @@ -22,9 +22,7 @@ use super::*; use crate::Pallet as Proxy; use alloc::{boxed::Box, vec}; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use sp_runtime::traits::Bounded; +use frame::benchmarking::prelude::*; const SEED: u32 = 0; @@ -80,24 +78,36 @@ fn add_announcements( Ok(()) } -benchmarks! { - proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn proxy(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - }: _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)) - verify { - assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)); + + assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()); + + Ok(()) } - proxy_announced { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn proxy_announced( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("pure", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); @@ -106,43 +116,65 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(delegate.clone()).into(), real_lookup.clone(), T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(delegate.clone()), None)?; - }: _(RawOrigin::Signed(caller), delegate_lookup, real_lookup, Some(T::ProxyType::default()), Box::new(call)) - verify { - assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) + + #[extrinsic_call] + _( + RawOrigin::Signed(caller), + delegate_lookup, + real_lookup, + Some(T::ProxyType::default()), + Box::new(call), + ); + + assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()); + + Ok(()) } - remove_announcement { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn remove_announcement( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup.clone(), T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(caller.clone()), real_lookup, T::CallHasher::hash_of(&call)) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), real_lookup, T::CallHasher::hash_of(&call)); + let (announcements, _) = Announcements::::get(&caller); assert_eq!(announcements.len() as u32, a); + + Ok(()) } - reject_announcement { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn reject_announcement( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); let caller_lookup = T::Lookup::unlookup(caller.clone()); @@ -150,22 +182,30 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup, T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(real), caller_lookup, T::CallHasher::hash_of(&call)) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(real), caller_lookup, T::CallHasher::hash_of(&call)); + let (announcements, _) = Announcements::::get(&caller); assert_eq!(announcements.len() as u32, a); + + Ok(()) } - announce { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn announce( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); @@ -173,74 +213,101 @@ benchmarks! { let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); add_announcements::(a, Some(caller.clone()), None)?; - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); let call_hash = T::CallHasher::hash_of(&call); - }: _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash); + assert_last_event::(Event::Announced { real, proxy: caller, call_hash }.into()); + + Ok(()) } - add_proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn add_proxy(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); let real = T::Lookup::unlookup(account("target", T::MaxProxies::get(), SEED)); - }: _( - RawOrigin::Signed(caller.clone()), - real, - T::ProxyType::default(), - BlockNumberFor::::zero() - ) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + real, + T::ProxyType::default(), + BlockNumberFor::::zero(), + ); + let (proxies, _) = Proxies::::get(caller); assert_eq!(proxies.len() as u32, p + 1); + + Ok(()) } - remove_proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn remove_proxy(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); let delegate = T::Lookup::unlookup(account("target", 0, SEED)); - }: _( - RawOrigin::Signed(caller.clone()), - delegate, - T::ProxyType::default(), - BlockNumberFor::::zero() - ) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + delegate, + T::ProxyType::default(), + BlockNumberFor::::zero(), + ); + let (proxies, _) = Proxies::::get(caller); assert_eq!(proxies.len() as u32, p - 1); + + Ok(()) } - remove_proxies { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn remove_proxies(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + let (proxies, _) = Proxies::::get(caller); assert_eq!(proxies.len() as u32, 0); + + Ok(()) } - create_pure { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn create_pure(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); - }: _( - RawOrigin::Signed(caller.clone()), - T::ProxyType::default(), - BlockNumberFor::::zero(), - 0 - ) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + T::ProxyType::default(), + BlockNumberFor::::zero(), + 0, + ); + let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); - assert_last_event::(Event::PureCreated { - pure: pure_account, - who: caller, - proxy_type: T::ProxyType::default(), - disambiguation_index: 0, - }.into()); - } + assert_last_event::( + Event::PureCreated { + pure: pure_account, + who: caller, + proxy_type: T::ProxyType::default(), + disambiguation_index: 0, + } + .into(), + ); - kill_pure { - let p in 0 .. (T::MaxProxies::get() - 2); + Ok(()) + } + #[benchmark] + fn kill_pure(p: Linear<0, { T::MaxProxies::get() - 2 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -248,17 +315,28 @@ benchmarks! { RawOrigin::Signed(whitelisted_caller()).into(), T::ProxyType::default(), BlockNumberFor::::zero(), - 0 + 0, )?; - let height = system::Pallet::::block_number(); - let ext_index = system::Pallet::::extrinsic_index().unwrap_or(0); + let height = frame_system::Pallet::::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); add_proxies::(p, Some(pure_account.clone()))?; ensure!(Proxies::::contains_key(&pure_account), "pure proxy not created"); - }: _(RawOrigin::Signed(pure_account.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(pure_account.clone()), + caller_lookup, + T::ProxyType::default(), + 0, + height, + ext_index, + ); + assert!(!Proxies::::contains_key(&pure_account)); + + Ok(()) } impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/substrate/frame/proxy/src/lib.rs b/substrate/frame/proxy/src/lib.rs index 016f2cf225e0..cc8aeedcc5f9 100644 --- a/substrate/frame/proxy/src/lib.rs +++ b/substrate/frame/proxy/src/lib.rs @@ -34,23 +34,12 @@ mod tests; pub mod weights; extern crate alloc; - use alloc::{boxed::Box, vec}; -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::GetDispatchInfo, - ensure, - traits::{Currency, Get, InstanceFilter, IsSubType, IsType, OriginTrait, ReservableCurrency}, - BoundedVec, +use frame::{ + prelude::*, + traits::{Currency, ReservableCurrency}, }; -use frame_system::{self as system, ensure_signed, pallet_prelude::BlockNumberFor}; pub use pallet::*; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - traits::{Dispatchable, Hash, Saturating, StaticLookup, TrailingZeroInput, Zero}, - DispatchError, DispatchResult, RuntimeDebug, -}; pub use weights::WeightInfo; type CallHashOf = <::CallHasher as Hash>::Output; @@ -96,11 +85,9 @@ pub struct Announcement { height: BlockNumber, } -#[frame_support::pallet] +#[frame::pallet] pub mod pallet { - use super::{DispatchResult, *}; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; + use super::*; #[pallet::pallet] pub struct Pallet(_); @@ -130,7 +117,7 @@ pub mod pallet { + Member + Ord + PartialOrd - + InstanceFilter<::RuntimeCall> + + frame::traits::InstanceFilter<::RuntimeCall> + Default + MaxEncodedLen; @@ -195,7 +182,7 @@ pub mod pallet { (T::WeightInfo::proxy(T::MaxProxies::get()) // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(di.weight), + .saturating_add(di.call_weight), di.class) })] pub fn proxy( @@ -392,7 +379,7 @@ pub mod pallet { let announcement = Announcement { real: real.clone(), call_hash, - height: system::Pallet::::block_number(), + height: frame_system::Pallet::::block_number(), }; Announcements::::try_mutate(&who, |(ref mut pending, ref mut deposit)| { @@ -487,7 +474,7 @@ pub mod pallet { (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(di.weight), + .saturating_add(di.call_weight), di.class) })] pub fn proxy_announced( @@ -503,7 +490,7 @@ pub mod pallet { let def = Self::find_proxy(&real, &delegate, force_proxy_type)?; let call_hash = T::CallHasher::hash_of(&call); - let now = system::Pallet::::block_number(); + let now = frame_system::Pallet::::block_number(); Self::edit_announcements(&delegate, |ann| { ann.real != real || ann.call_hash != call_hash || @@ -639,8 +626,8 @@ impl Pallet { ) -> T::AccountId { let (height, ext_index) = maybe_when.unwrap_or_else(|| { ( - system::Pallet::::block_number(), - system::Pallet::::extrinsic_index().unwrap_or_default(), + frame_system::Pallet::::block_number(), + frame_system::Pallet::::extrinsic_index().unwrap_or_default(), ) }); let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index) @@ -796,6 +783,7 @@ impl Pallet { real: T::AccountId, call: ::RuntimeCall, ) { + use frame::traits::{InstanceFilter as _, OriginTrait as _}; // This is a freshly authenticated new account, the origin restrictions doesn't apply. let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into(); origin.add_filter(move |c: &::RuntimeCall| { diff --git a/substrate/frame/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 3edb96026a82..5baf9bb9e838 100644 --- a/substrate/frame/proxy/src/tests.rs +++ b/substrate/frame/proxy/src/tests.rs @@ -20,22 +20,14 @@ #![cfg(test)] use super::*; - use crate as proxy; use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode}; -use frame_support::{ - assert_noop, assert_ok, derive_impl, - traits::{ConstU32, ConstU64, Contains}, -}; -use sp_core::H256; -use sp_runtime::{traits::BlakeTwo256, BuildStorage, DispatchError, RuntimeDebug}; +use frame::testing_prelude::*; type Block = frame_system::mocking::MockBlock; -frame_support::construct_runtime!( - pub enum Test - { +construct_runtime!( + pub struct Test { System: frame_system, Balances: pallet_balances, Proxy: proxy, @@ -86,7 +78,7 @@ impl Default for ProxyType { Self::Any } } -impl InstanceFilter for ProxyType { +impl frame::traits::InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, @@ -136,20 +128,20 @@ use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; type SystemError = frame_system::Error; -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestState { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 3)], } .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); + let mut ext = TestState::new(t); ext.execute_with(|| System::set_block_number(1)); ext } fn last_events(n: usize) -> Vec { - system::Pallet::::events() + frame_system::Pallet::::events() .into_iter() .rev() .take(n) @@ -286,7 +278,7 @@ fn delayed_requires_pre_announcement() { assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone()), e); let call_hash = BlakeTwo256::hash_of(&call); assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); - system::Pallet::::set_block_number(2); + frame_system::Pallet::::set_block_number(2); assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone())); }); } @@ -304,7 +296,7 @@ fn proxy_announced_removes_announcement_and_returns_deposit() { let e = Error::::Unannounced; assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone()), e); - system::Pallet::::set_block_number(2); + frame_system::Pallet::::set_block_number(2); assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone())); let announcements = Announcements::::get(3); assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash, height: 1 }]); diff --git a/substrate/frame/proxy/src/weights.rs b/substrate/frame/proxy/src/weights.rs index 3093298e3e54..851c0ba98a82 100644 --- a/substrate/frame/proxy/src/weights.rs +++ b/substrate/frame/proxy/src/weights.rs @@ -46,8 +46,7 @@ #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; +use frame::weights_prelude::*; /// Weight functions needed for `pallet_proxy`. pub trait WeightInfo { @@ -412,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/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/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 69be4df971bc..f8622880538e 100644 --- a/substrate/frame/recovery/src/lib.rs +++ b/substrate/frame/recovery/src/lib.rs @@ -378,7 +378,7 @@ pub mod pallet { #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( - T::WeightInfo::as_recovered().saturating_add(dispatch_info.weight), + T::WeightInfo::as_recovered().saturating_add(dispatch_info.call_weight), dispatch_info.class, )})] pub fn as_recovered( 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..e9b4eb04ed51 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -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/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 177b3c3e9eec..81fbbc8cf38e 100644 --- a/substrate/frame/revive/Cargo.toml +++ b/substrate/frame/revive/Cargo.toml @@ -19,40 +19,52 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] environmental = { workspace = true } paste = { workspace = true } -polkavm = { version = "0.11.0", default-features = false } +polkavm = { version = "0.13.0", default-features = false } bitflags = { workspace = true } -codec = { features = [ - "derive", - "max-encoded-len", -], workspace = true } +codec = { features = ["derive", "max-encoded-len"], workspace = true } scale-info = { features = ["derive"], workspace = true } log = { workspace = true } -serde = { optional = true, features = ["derive"], workspace = true, default-features = 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-fixtures = { workspace = true, default-features = false, optional = true } pallet-revive-uapi = { workspace = true, default-features = true } pallet-revive-proc-macro = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true } sp-api = { workspace = true } +sp-arithmetic = { workspace = true } 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", +] } [dev-dependencies] array-bytes = { workspace = true, default-features = true } assert_matches = { workspace = true } pretty_assertions = { workspace = true } -wat = { 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 } @@ -67,32 +79,37 @@ xcm-builder = { workspace = true, default-features = true } [features] default = ["std"] -# enabling this feature will require having a riscv toolchain installed -# if no tests are ran and runtime benchmarks will not work -# apart from this the pallet will stay functional -riscv = ["pallet-revive-fixtures/riscv"] std = [ "codec/std", "environmental/std", + "ethereum-types/std", "frame-benchmarking?/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", "polkavm/std", "rlp/std", "scale-info/std", - "serde", + "secp256k1/std", + "serde/std", + "serde_json/std", "sp-api/std", + "sp-arithmetic/std", "sp-core/std", "sp-io/std", "sp-keystore/std", "sp-runtime/std", "sp-std/std", + "sp-weights/std", + "subxt-signer", "xcm-builder/std", "xcm/std", ] @@ -104,7 +121,9 @@ 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", @@ -117,6 +136,7 @@ try-runtime = [ "pallet-message-queue/try-runtime", "pallet-proxy/try-runtime", "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", "sp-runtime/try-runtime", ] diff --git a/substrate/frame/revive/fixtures/Cargo.toml b/substrate/frame/revive/fixtures/Cargo.toml index 53db08a3911a..7a5452853d65 100644 --- a/substrate/frame/revive/fixtures/Cargo.toml +++ b/substrate/frame/revive/fixtures/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "pallet-revive-fixtures" -publish = true version = "0.1.0" authors.workspace = true edition.workspace = true @@ -22,21 +21,10 @@ log = { workspace = true } parity-wasm = { workspace = true } tempfile = { workspace = true } toml = { workspace = true } -polkavm-linker = { version = "0.11.0" } +polkavm-linker = { version = "0.14.0" } anyhow = { workspace = true, default-features = true } [features] default = ["std"] -# only if the feature is set we are building the test fixtures -# this is because it requires a custom toolchain supporting polkavm -# we will remove this once there is an upstream toolchain -riscv = [] # only when std is enabled all fixtures are available -std = [ - "anyhow", - "frame-system", - "log/std", - "sp-core", - "sp-io", - "sp-runtime", -] +std = ["anyhow", "frame-system", "log/std", "sp-core", "sp-io", "sp-runtime"] diff --git a/substrate/frame/revive/fixtures/build.rs b/substrate/frame/revive/fixtures/build.rs index 944ae246c1b8..3472e0846efd 100644 --- a/substrate/frame/revive/fixtures/build.rs +++ b/substrate/frame/revive/fixtures/build.rs @@ -18,198 +18,206 @@ //! Compile text fixtures to PolkaVM binaries. use anyhow::Result; -fn main() -> Result<()> { - build::run() +use anyhow::{bail, Context}; +use std::{ + cfg, env, fs, + path::{Path, PathBuf}, + process::Command, +}; + +const OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_RUSTUP_TOOLCHAIN"; +const OVERRIDE_STRIP_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_STRIP"; +const OVERRIDE_OPTIMIZE_ENV_VAR: &str = "PALLET_REVIVE_FIXTURES_OPTIMIZE"; + +/// A contract entry. +struct Entry { + /// The path to the contract source file. + path: PathBuf, } -#[cfg(feature = "riscv")] -mod build { - use super::Result; - use anyhow::{bail, Context}; - use std::{ - cfg, env, fs, - path::{Path, PathBuf}, - process::Command, - }; - - /// A contract entry. - struct Entry { - /// The path to the contract source file. - path: PathBuf, +impl Entry { + /// Create a new contract entry from the given path. + fn new(path: PathBuf) -> Self { + Self { path } } - impl Entry { - /// Create a new contract entry from the given path. - fn new(path: PathBuf) -> Self { - Self { path } - } - - /// Return the path to the contract source file. - fn path(&self) -> &str { - self.path.to_str().expect("path is valid unicode; qed") - } - - /// Return the name of the contract. - fn name(&self) -> &str { - self.path - .file_stem() - .expect("file exits; qed") - .to_str() - .expect("name is valid unicode; qed") - } + /// Return the path to the contract source file. + fn path(&self) -> &str { + self.path.to_str().expect("path is valid unicode; qed") + } - /// Return the name of the polkavm file. - fn out_filename(&self) -> String { - format!("{}.polkavm", self.name()) - } + /// Return the name of the contract. + fn name(&self) -> &str { + self.path + .file_stem() + .expect("file exits; qed") + .to_str() + .expect("name is valid unicode; qed") } - /// Collect all contract entries from the given source directory. - /// Contracts that have already been compiled are filtered out. - fn collect_entries(contracts_dir: &Path) -> Vec { - fs::read_dir(contracts_dir) - .expect("src dir exists; qed") - .filter_map(|file| { - let path = file.expect("file exists; qed").path(); - if path.extension().map_or(true, |ext| ext != "rs") { - return None - } - - Some(Entry::new(path)) - }) - .collect::>() + /// Return the name of the polkavm file. + fn out_filename(&self) -> String { + format!("{}.polkavm", self.name()) } +} - /// Create a `Cargo.toml` to compile the given contract entries. - fn create_cargo_toml<'a>( - fixtures_dir: &Path, - entries: impl Iterator, - output_dir: &Path, - ) -> Result<()> { - 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(), - ); - Ok(()) - }; - set_dep("uapi", "../uapi")?; - set_dep("common", "./contracts/common")?; - - cargo_toml["bin"] = toml::Value::Array( - entries - .map(|entry| { - let name = entry.name(); - let path = entry.path(); - toml::Value::Table(toml::toml! { - name = name - path = path - }) - }) - .collect::>(), +/// Collect all contract entries from the given source directory. +fn collect_entries(contracts_dir: &Path) -> Vec { + fs::read_dir(contracts_dir) + .expect("src dir exists; qed") + .filter_map(|file| { + let path = file.expect("file exists; qed").path(); + if path.extension().map_or(true, |ext| ext != "rs") { + return None + } + + Some(Entry::new(path)) + }) + .collect::>() +} + +/// Create a `Cargo.toml` to compile the given contract entries. +fn create_cargo_toml<'a>( + fixtures_dir: &Path, + entries: impl Iterator, + output_dir: &Path, +) -> Result<()> { + 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(), ); + Ok(()) + }; + set_dep("uapi", "../uapi")?; + set_dep("common", "./contracts/common")?; + + cargo_toml["bin"] = toml::Value::Array( + entries + .map(|entry| { + let name = entry.name(); + let path = entry.path(); + toml::Value::Table(toml::toml! { + name = name + path = path + }) + }) + .collect::>(), + ); - let cargo_toml = toml::to_string_pretty(&cargo_toml)?; - fs::write(output_dir.join("Cargo.toml"), cargo_toml).map_err(Into::into) + let cargo_toml = toml::to_string_pretty(&cargo_toml)?; + fs::write(output_dir.join("Cargo.toml"), cargo_toml.clone()) + .with_context(|| format!("Failed to write {cargo_toml:?}"))?; + Ok(()) +} + +fn invoke_build(target: &Path, current_dir: &Path) -> Result<()> { + let encoded_rustflags = ["-Dwarnings"].join("\x1f"); + + let mut build_command = Command::new(env::var("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()) + .env("RUSTUP_TOOLCHAIN", env::var("RUSTUP_TOOLCHAIN").unwrap_or_default()) + .args([ + "build", + "--release", + "-Zbuild-std=core", + "-Zbuild-std-features=panic_immediate_abort", + ]) + .arg("--target") + .arg(target); + + if let Ok(toolchain) = env::var(OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR) { + build_command.env("RUSTUP_TOOLCHAIN", &toolchain); } - fn invoke_build(current_dir: &Path) -> Result<()> { - let encoded_rustflags = [ - "-Crelocation-model=pie", - "-Clink-arg=--emit-relocs", - "-Clink-arg=--export-dynamic-symbol=__polkavm_symbol_export_hack__*", - ] - .join("\x1f"); - - let build_res = Command::new(env::var("CARGO")?) - .current_dir(current_dir) - .env_clear() - .env("PATH", env::var("PATH").unwrap_or_default()) - .env("CARGO_ENCODED_RUSTFLAGS", encoded_rustflags) - .env("RUSTUP_TOOLCHAIN", "rve-nightly") - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTUP_HOME", env::var("RUSTUP_HOME").unwrap_or_default()) - .args([ - "build", - "--release", - "--target=riscv32ema-unknown-none-elf", - "-Zbuild-std=core", - "-Zbuild-std-features=panic_immediate_abort", - ]) - .output() - .expect("failed to execute process"); - - if build_res.status.success() { - return Ok(()) - } + let build_res = build_command.output().expect("failed to execute process"); - let stderr = String::from_utf8_lossy(&build_res.stderr); + if build_res.status.success() { + return Ok(()) + } - if stderr.contains("'rve-nightly' is not installed") { - eprintln!("RISC-V toolchain is not installed.\nDownload and install toolchain from https://github.com/paritytech/rustc-rv32e-toolchain."); - eprintln!("{}", stderr); - } else { - eprintln!("{}", stderr); - } + let stderr = String::from_utf8_lossy(&build_res.stderr); + eprintln!("{}", stderr); - bail!("Failed to build contracts"); - } + bail!("Failed to build contracts"); +} + +/// Post-process the compiled code. +fn post_process(input_path: &Path, output_path: &Path) -> Result<()> { + 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 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).with_context(|| format!("Failed to write {output_path:?}"))?; + Ok(()) +} - /// Post-process the compiled code. - fn post_process(input_path: &Path, output_path: &Path) -> Result<()> { - let mut config = polkavm_linker::Config::default(); - config.set_strip(true); - config.set_optimize(false); - 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) +/// Write the compiled contracts to the given output directory. +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(entry.name()), + &out_dir.join(entry.out_filename()), + )?; } - /// Write the compiled contracts to the given output directory. - fn write_output(build_dir: &Path, out_dir: &Path, entries: Vec) -> Result<()> { - for entry in entries { - post_process( - &build_dir.join("target/riscv32ema-unknown-none-elf/release").join(entry.name()), - &out_dir.join(entry.out_filename()), - )?; - } + Ok(()) +} - Ok(()) - } +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"); - pub fn run() -> Result<()> { - let fixtures_dir: PathBuf = env::var("CARGO_MANIFEST_DIR")?.into(); - let contracts_dir = fixtures_dir.join("contracts"); - let uapi_dir = fixtures_dir.parent().expect("uapi dir exits; qed").join("uapi"); - let out_dir: PathBuf = env::var("OUT_DIR")?.into(); + println!("cargo::rerun-if-env-changed={OVERRIDE_RUSTUP_TOOLCHAIN_ENV_VAR}"); + println!("cargo::rerun-if-env-changed={OVERRIDE_STRIP_ENV_VAR}"); + println!("cargo::rerun-if-env-changed={OVERRIDE_OPTIMIZE_ENV_VAR}"); - // the fixtures have a dependency on the uapi crate - println!("cargo::rerun-if-changed={}", fixtures_dir.display()); + // the fixtures have a dependency on the uapi crate + println!("cargo::rerun-if-changed={}", fixtures_dir.display()); + let uapi_dir = fixtures_dir.parent().expect("parent dir exits; qed").join("uapi"); + if uapi_dir.exists() { println!("cargo::rerun-if-changed={}", uapi_dir.display()); + } - let entries = collect_entries(&contracts_dir); - if entries.is_empty() { - return Ok(()) - } - - let tmp_dir = tempfile::tempdir()?; - let tmp_dir_path = tmp_dir.path(); + let entries = collect_entries(&contracts_dir); + if entries.is_empty() { + return Ok(()) + } - create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?; - invoke_build(tmp_dir_path)?; + let tmp_dir = tempfile::tempdir()?; + let tmp_dir_path = tmp_dir.path(); - write_output(tmp_dir_path, &out_dir, entries)?; - Ok(()) - } -} + create_cargo_toml(&fixtures_dir, entries.iter(), tmp_dir.path())?; + invoke_build(&target, tmp_dir_path)?; -#[cfg(not(feature = "riscv"))] -mod build { - use super::Result; + write_output(tmp_dir_path, &out_dir, entries)?; - pub fn run() -> Result<()> { - Ok(()) + #[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) + .with_context(|| format!("Failed to remove_file {symlink_dir:?}"))?; + } + std::os::unix::fs::symlink(&out_dir, &symlink_dir) + .with_context(|| format!("Failed to symlink {out_dir:?} -> {symlink_dir:?}"))?; } + + Ok(()) } diff --git a/substrate/frame/revive/fixtures/build/Cargo.toml b/substrate/frame/revive/fixtures/build/Cargo.toml index 5b3a21b5122e..5d0e256e2e73 100644 --- a/substrate/frame/revive/fixtures/build/Cargo.toml +++ b/substrate/frame/revive/fixtures/build/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" [dependencies] uapi = { package = 'pallet-revive-uapi', path = "", default-features = false } common = { package = 'pallet-revive-fixtures-common', path = "" } -polkavm-derive = { version = "0.11.0" } +polkavm-derive = { version = "0.14.0" } [profile.release] opt-level = 3 diff --git a/substrate/frame/revive/fixtures/contracts/basic_block.rs b/substrate/frame/revive/fixtures/contracts/basic_block.rs new file mode 100644 index 000000000000..0cde7a264632 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/basic_block.rs @@ -0,0 +1,47 @@ +// 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. + +//! Create a basic block that is larger than we allow. + +#![no_std] +#![no_main] + +extern crate common; + +use core::arch::asm; + +// 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() { + // Stores cannot be optimized away because the optimizer cannot + // know whether they have side effects. + let value: u32 = 42; + unsafe { + // Repeat 1001 times to intentionally exceed the allowed basic block limit (1000) + asm!(".rept 1001", "sw {x}, 0(sp)", ".endr", x = in(reg) value); + } +} + +#[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/block_hash.rs b/substrate/frame/revive/fixtures/contracts/block_hash.rs new file mode 100644 index 000000000000..1331c4601463 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/block_hash.rs @@ -0,0 +1,37 @@ +// 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; +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + input!(block_number: &[u8; 32], block_hash: &[u8; 32],); + + let mut buf = [0; 32]; + api::block_hash(block_number, &mut &mut buf); + + assert_eq!(&buf[..], block_hash); +} diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index e13162f8fb43..129adde2cec9 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -26,7 +26,8 @@ #![no_std] #![no_main] -use common::input; +extern crate common; + use uapi::{HostFn, HostFnImpl as api}; const BUF_SIZE: usize = 8; @@ -36,7 +37,7 @@ static DATA: [u8; BUF_SIZE] = [1, 2, 3, 4, 5, 6, 7, 8]; /// and expect the call output to match `expected_output`. fn assert_call(callee_address: &[u8; 20], expected_output: [u8; BUF_SIZE]) { let mut output_buf = [0u8; BUF_SIZE]; - let mut output_buf_capped = &mut &mut output_buf[..N]; + let output_buf_capped = &mut &mut output_buf[..N]; api::call( uapi::CallFlags::ALLOW_REENTRY, @@ -62,7 +63,7 @@ fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { api::own_code_hash(&mut code_hash); let mut output_buf = [0u8; BUF_SIZE]; - let mut output_buf_capped = &mut &mut output_buf[..N]; + let output_buf_capped = &mut &mut output_buf[..N]; api::instantiate( &code_hash, diff --git a/substrate/frame/revive/fixtures/contracts/call_return_code.rs b/substrate/frame/revive/fixtures/contracts/call_return_code.rs index d0d7c1bee2a5..2d13b9f70956 100644 --- a/substrate/frame/revive/fixtures/contracts/call_return_code.rs +++ b/substrate/frame/revive/fixtures/contracts/call_return_code.rs @@ -21,7 +21,7 @@ #![no_std] #![no_main] -use common::{input, u256_bytes}; +use common::input; use uapi::{HostFn, HostFnImpl as api}; #[no_mangle] diff --git a/substrate/frame/revive/fixtures/contracts/code_hash.rs b/substrate/frame/revive/fixtures/contracts/code_hash.rs new file mode 100644 index 000000000000..b598a485a8c7 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/code_hash.rs @@ -0,0 +1,40 @@ +// 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; +use uapi::{HostFn, HostFnImpl as api}; + +#[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], + expected_code_hash: &[u8; 32], + ); + + let mut code_hash = [0u8; 32]; + api::code_hash(address, &mut code_hash); + + assert!(&code_hash == expected_code_hash); +} 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..55203d534c9b --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs @@ -0,0 +1,46 @@ +// 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]; + api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, Some(&u256_bytes(deposit_limit)), &input, None).unwrap(); + + 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 new file mode 100644 index 000000000000..0a1171be30e9 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/extcodesize.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. + +#![no_std] +#![no_main] + +use common::{input, u64_output}; +use uapi::{HostFn, HostFnImpl as api}; + +#[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], expected: u64,); + + let received = u64_output!(api::code_size, address); + + assert_eq!(expected, received); +} diff --git a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs index 2efacb4e683f..3d7702c6537a 100644 --- a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs +++ b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs @@ -23,13 +23,14 @@ use common::input; use uapi::{HostFn, HostFnImpl as api}; -const ETH_ALICE: [u8; 20] = [1u8; 20]; +const ALICE_FALLBACK: [u8; 20] = [1u8; 20]; /// Load input data and perform the action specified by the input. /// If `delegate_call` is true, then delegate call into the contract. fn load_input(delegate_call: bool) { input!( action: u32, + address: &[u8; 20], code_hash: &[u8; 32], ); @@ -44,14 +45,14 @@ fn load_input(delegate_call: bool) { }, // 3 = Terminate 3 => { - api::terminate(Ð_ALICE); + api::terminate(&ALICE_FALLBACK); }, // Everything else is a noop _ => {}, } 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/oom_rw_included.rs b/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs index 2cdcf7bafed1..123ee38a5200 100644 --- a/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs +++ b/substrate/frame/revive/fixtures/contracts/oom_rw_included.rs @@ -28,11 +28,16 @@ use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; static mut BUFFER: [u8; 513 * 1024] = [42; 513 * 1024]; +unsafe fn buffer() -> &'static [u8; 513 * 1024] { + let ptr = core::ptr::addr_of!(BUFFER); + &*ptr +} + #[no_mangle] #[polkavm_derive::polkavm_export] pub unsafe extern "C" fn call_never() { // make sure the buffer is not optimized away - api::return_value(ReturnFlags::empty(), &BUFFER); + api::return_value(ReturnFlags::empty(), buffer()); } #[no_mangle] diff --git a/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs b/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs index 993be8e9cda4..e127effca20c 100644 --- a/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs +++ b/substrate/frame/revive/fixtures/contracts/oom_rw_trailing.rs @@ -26,13 +26,18 @@ extern crate common; use uapi::{HostFn, HostFnImpl as api, ReturnFlags}; -static mut BUFFER: [u8; 1025 * 1024] = [0; 1025 * 1024]; +static mut BUFFER: [u8; 2 * 1025 * 1024] = [0; 2 * 1025 * 1024]; + +unsafe fn buffer() -> &'static [u8; 2 * 1025 * 1024] { + let ptr = core::ptr::addr_of!(BUFFER); + &*ptr +} #[no_mangle] #[polkavm_derive::polkavm_export] pub unsafe extern "C" fn call_never() { // make sure the buffer is not optimized away - api::return_value(ReturnFlags::empty(), &BUFFER); + api::return_value(ReturnFlags::empty(), buffer()); } #[no_mangle] diff --git a/substrate/frame/revive/fixtures/contracts/origin.rs b/substrate/frame/revive/fixtures/contracts/origin.rs new file mode 100644 index 000000000000..8e9afd8e8052 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/origin.rs @@ -0,0 +1,62 @@ +// 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. + +//! Tests that the `origin` syscall works. +//! The fixture returns the observed origin if the caller is not the origin, +//! otherwise call itself recursively and assert the returned origin to match. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut caller = [0; 20]; + api::caller(&mut caller); + + let mut origin = [0; 20]; + api::origin(&mut origin); + + if caller != origin { + api::return_value(Default::default(), &origin); + } + + let mut addr = [0u8; 20]; + api::address(&mut addr); + + let mut buf = [0u8; 20]; + api::call( + uapi::CallFlags::ALLOW_REENTRY, + &addr, + 0u64, + 0u64, + None, + &[0; 32], + &[], + Some(&mut &mut buf[..]), + ) + .unwrap(); + + assert_eq!(buf, origin); +} diff --git a/substrate/frame/revive/fixtures/contracts/return_data_api.rs b/substrate/frame/revive/fixtures/contracts/return_data_api.rs index 846396b0944d..2a390296a419 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,22 +73,6 @@ 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]; @@ -96,11 +80,11 @@ fn assert_return_data_size_of(expected: u64) { assert_eq!(return_data_size, u256_bytes(expected)); } -/// Assert [api::return_data_size] to match the `expected` value after a plain transfer -/// (plain transfers don't issue a call and so should not reset the return data) -fn assert_plain_transfer_does_not_reset(expected: u64) { - api::transfer(&[0; 20], &u256_bytes(128)).unwrap(); - assert_return_data_size_of(expected); +/// 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 new file mode 100644 index 000000000000..4c61f2ea82ec --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/rpc_demo.rs @@ -0,0 +1,42 @@ +// 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, u64_output}; +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() { + input!(128, data: [u8],); + api::deposit_event(&[], data); +} + +#[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/sbrk.rs b/substrate/frame/revive/fixtures/contracts/sbrk.rs new file mode 100644 index 000000000000..5b0bba99df81 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/sbrk.rs @@ -0,0 +1,39 @@ +// 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. + +//! Uses the sbrk instruction in order to test that it is rejected. + +#![no_std] +#![no_main] + +extern crate common; + +// 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() { + polkavm_derive::sbrk(4); +} + +#[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/self_destruct.rs b/substrate/frame/revive/fixtures/contracts/self_destruct.rs index 524979991ec7..2f37706634bd 100644 --- a/substrate/frame/revive/fixtures/contracts/self_destruct.rs +++ b/substrate/frame/revive/fixtures/contracts/self_destruct.rs @@ -21,7 +21,7 @@ use common::input; use uapi::{HostFn, HostFnImpl as api}; -const ETH_DJANGO: [u8; 20] = [4u8; 20]; +const DJANGO_FALLBACK: [u8; 20] = [4u8; 20]; #[no_mangle] #[polkavm_derive::polkavm_export] @@ -52,6 +52,6 @@ pub extern "C" fn call() { .unwrap(); } else { // Try to terminate and give balance to django. - api::terminate(Ð_DJANGO); + api::terminate(&DJANGO_FALLBACK); } } diff --git a/substrate/frame/revive/fixtures/contracts/terminate_and_send_to_eve.rs b/substrate/frame/revive/fixtures/contracts/terminate_and_send_to_eve.rs new file mode 100644 index 000000000000..c078f9d46c1d --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/terminate_and_send_to_eve.rs @@ -0,0 +1,33 @@ +// 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}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let eve = [5u8; 20]; + api::terminate(&eve); +} 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/riscv32emac-unknown-none-polkavm.json b/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json new file mode 100644 index 000000000000..bbd54cdefbac --- /dev/null +++ b/substrate/frame/revive/fixtures/riscv32emac-unknown-none-polkavm.json @@ -0,0 +1,26 @@ +{ + "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 5548dca66d07..cc84daec9b59 100644 --- a/substrate/frame/revive/fixtures/src/lib.rs +++ b/substrate/frame/revive/fixtures/src/lib.rs @@ -37,18 +37,11 @@ pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec, sp_core::H pub mod bench { use alloc::vec::Vec; - #[cfg(feature = "riscv")] macro_rules! fixture { ($name: literal) => { include_bytes!(concat!(env!("OUT_DIR"), "/", $name, ".polkavm")) }; } - #[cfg(not(feature = "riscv"))] - macro_rules! fixture { - ($name: literal) => { - &[] - }; - } pub const DUMMY: &[u8] = fixture!("dummy"); pub const NOOP: &[u8] = fixture!("noop"); pub const INSTR: &[u8] = fixture!("instr_benchmark"); diff --git a/substrate/frame/revive/mock-network/Cargo.toml b/substrate/frame/revive/mock-network/Cargo.toml index 85656a57b49c..c5b18b3fa290 100644 --- a/substrate/frame/revive/mock-network/Cargo.toml +++ b/substrate/frame/revive/mock-network/Cargo.toml @@ -48,7 +48,6 @@ pallet-revive-fixtures = { workspace = true } [features] default = ["std"] -riscv = ["pallet-revive-fixtures/riscv"] std = [ "codec/std", "frame-support/std", @@ -87,3 +86,17 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/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-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/lib.rs b/substrate/frame/revive/mock-network/src/lib.rs index 848994653972..adfd0016b4dd 100644 --- a/substrate/frame/revive/mock-network/src/lib.rs +++ b/substrate/frame/revive/mock-network/src/lib.rs @@ -19,7 +19,7 @@ pub mod parachain; pub mod primitives; pub mod relay_chain; -#[cfg(all(test, feature = "riscv"))] +#[cfg(test)] mod tests; use crate::primitives::{AccountId, UNITS}; diff --git a/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs b/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs index c13c337d1667..a2fa7cbf7068 100644 --- a/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs +++ b/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs @@ -20,7 +20,7 @@ use frame_support::derive_impl; #[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)] impl pallet_revive::Config for Runtime { - type AddressMapper = pallet_revive::DefaultAddressMapper; + type AddressMapper = pallet_revive::AccountId32Mapper; type Currency = Balances; type Time = super::Timestamp; type Xcm = pallet_xcm::Pallet; diff --git a/substrate/frame/revive/rpc/.dockerignore b/substrate/frame/revive/rpc/.dockerignore new file mode 100644 index 000000000000..c58599e3fb72 --- /dev/null +++ b/substrate/frame/revive/rpc/.dockerignore @@ -0,0 +1,7 @@ +doc +**target* +.idea/ +Dockerfile +.dockerignore +.local +.env* diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml new file mode 100644 index 000000000000..9f89b74c668f --- /dev/null +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -0,0 +1,81 @@ +[package] +name = "pallet-revive-eth-rpc" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "An Ethereum JSON-RPC server for pallet-revive." + +[[bin]] +name = "eth-rpc" +path = "src/main.rs" + +[[example]] +name = "deploy" +path = "examples/rust/deploy.rs" +required-features = ["example"] + +[[example]] +name = "transfer" +path = "examples/rust/transfer.rs" +required-features = ["example"] + +[[example]] +name = "rpc-playground" +path = "examples/rust/rpc-playground.rs" +required-features = ["example"] + +[[example]] +name = "extrinsic" +path = "examples/rust/extrinsic.rs" +required-features = ["example"] + +[[example]] +name = "remark-extrinsic" +path = "examples/rust/remark-extrinsic.rs" +required-features = ["example"] + +[dependencies] +clap = { workspace = true, features = ["derive"] } +anyhow = { workspace = true } +futures = { workspace = true, features = ["thread-pool"] } +jsonrpsee = { workspace = true, features = ["full"] } +serde_json = { workspace = true } +thiserror = { workspace = true } +sp-crypto-hashing = { workspace = true } +subxt = { workspace = true, default-features = true, features = ["reconnecting-rpc-client"] } +tokio = { workspace = true, features = ["full"] } +codec = { workspace = true, features = ["derive"] } +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-rpc-api = { 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 } +subxt-signer = { workspace = true, optional = true, features = [ + "unstable-eth", +] } +hex = { workspace = true } +hex-literal = { workspace = true, optional = true } +scale-info = { workspace = true } +secp256k1 = { workspace = true, optional = true, features = ["recovery"] } +env_logger = { workspace = true } +ethabi = { version = "18.0.0" } + +[features] +example = ["hex-literal", "rlp", "secp256k1", "subxt-signer"] + +[dev-dependencies] +static_init = { workspace = true } +hex-literal = { workspace = true } +pallet-revive-fixtures = { workspace = true } +substrate-cli-test-utils = { workspace = true } +subxt-signer = { workspace = true, features = ["unstable-eth"] } diff --git a/substrate/frame/revive/rpc/Dockerfile b/substrate/frame/revive/rpc/Dockerfile new file mode 100644 index 000000000000..fb867062a818 --- /dev/null +++ b/substrate/frame/revive/rpc/Dockerfile @@ -0,0 +1,31 @@ +FROM rust AS builder + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + protobuf-compiler \ + clang libclang-dev + +WORKDIR /polkadot +COPY . /polkadot +RUN rustup component add rust-src +RUN cargo build --locked --profile production -p pallet-revive-eth-rpc --bin eth-rpc + +FROM docker.io/parity/base-bin:latest +COPY --from=builder /polkadot/target/production/eth-rpc /usr/local/bin + +USER root +RUN useradd -m -u 1001 -U -s /bin/sh -d /polkadot polkadot && \ +# unclutter and minimize the attack surface + rm -rf /usr/bin /usr/sbin && \ +# check if executable works in this container + /usr/local/bin/eth-rpc --help + +USER polkadot + +# 8545 is the default port for the RPC server +# 9616 is the default port for the prometheus metrics +EXPOSE 8545 9616 +ENTRYPOINT ["/usr/local/bin/eth-rpc"] + +# We call the help by default +CMD ["--help"] diff --git a/substrate/frame/revive/rpc/examples/README.md b/substrate/frame/revive/rpc/examples/README.md new file mode 100644 index 000000000000..b9a2756b381d --- /dev/null +++ b/substrate/frame/revive/rpc/examples/README.md @@ -0,0 +1,70 @@ +## Pre-requisites + + Build `pallet-revive-fixture`, as we need some compiled contracts to exercise the RPC server. + +```bash +cargo build -p pallet-revive-fixtures +``` + +## Start the node + +Start the kitchensink node: + +```bash +RUST_LOG="error,evm=debug,sc_rpc_server=info,runtime::revive=debug" cargo run --bin substrate-node -- --dev +``` + +## Start a zombienet network + +Alternatively, you can start a zombienet network with the westend Asset Hub parachain: + +Prerequisites for running a local network: +- download latest [zombienet release](https://github.com/paritytech/zombienet/releases); +- build Polkadot binary by running `cargo build -p polkadot --release --features fast-runtime` command in the + [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; +- build Polkadot Parachain binary by running `cargo build -p polkadot-parachain-bin --release` command in the + [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + +```bash +zombienet spawn --provider native westend_local_network.toml +``` + +## Start the RPC server + +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 -- --dev +``` + +## Rust examples + +Run one of the examples from the `examples` directory to send a transaction to the node: + +```bash +RUST_LOG="info,eth-rpc=debug" cargo run -p pallet-revive-eth-rpc --features example --example deploy +``` + +## JS examples + +Interact with the node using MetaMask & Ether.js, by starting the example web app: + +```bash + +cd substrate/frame/revive/rpc/examples/js +bun install +bun run dev +``` + +Alternatively, you can run the example script directly: + +```bash +cd substrate/frame/revive/rpc/examples/js +bun src/script.ts +``` + +### Configure MetaMask + +See the doc [here](https://contracts.polkadot.io/work-with-a-local-node#metemask-configuration) for more +information on how to configure MetaMask. + 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/.gitignore b/substrate/frame/revive/rpc/examples/js/.gitignore new file mode 100644 index 000000000000..a547bf36d8d1 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? 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/event.json b/substrate/frame/revive/rpc/examples/js/abi/event.json new file mode 100644 index 000000000000..d36089fbc84e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/event.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" + } +] 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..2c2cfd5f7533 --- /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" + } +] diff --git a/substrate/frame/revive/rpc/examples/js/abi/revert.json b/substrate/frame/revive/rpc/examples/js/abi/revert.json new file mode 100644 index 000000000000..be2945fcc0a5 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/abi/revert.json @@ -0,0 +1,14 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "doRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/substrate/frame/revive/rpc/examples/js/bun.lockb b/substrate/frame/revive/rpc/examples/js/bun.lockb new file mode 100755 index 000000000000..700dca51da2a Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/bun.lockb differ 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/PiggyBank.sol b/substrate/frame/revive/rpc/examples/js/contracts/PiggyBank.sol new file mode 100644 index 000000000000..1906c4658889 --- /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 { + + uint private balance; + address public owner; + + constructor() { + owner = msg.sender; + balance = 0; + } + + function deposit() public payable returns (uint) { + balance += msg.value; + return balance; + } + + function getDeposit() public view returns (uint) { + return balance; + } + + function withdraw(uint withdrawAmount) public returns (uint 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/contracts/Revert.sol b/substrate/frame/revive/rpc/examples/js/contracts/Revert.sol new file mode 100644 index 000000000000..53f1f8994256 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/contracts/Revert.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract RevertExample { + constructor() { + } + + function doRevert() public { + revert("revert message"); + } +} diff --git a/substrate/frame/revive/rpc/examples/js/index.html b/substrate/frame/revive/rpc/examples/js/index.html new file mode 100644 index 000000000000..97efebe180ea --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/index.html @@ -0,0 +1,38 @@ + + + + + + + MetaMask Playground + + + + + + + + + + + + + + + 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 new file mode 100644 index 000000000000..3ae1f0fbd799 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/package.json @@ -0,0 +1,22 @@ +{ + "name": "demo", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "generate-types": "typechain --target=ethers-v6 'abi/*.json'" + }, + "dependencies": { + "@typechain/ethers-v6": "^0.5.1", + "ethers": "^6.13.4", + "solc": "^0.8.28", + "typechain": "^8.3.2" + }, + "devDependencies": { + "typescript": "^5.5.3", + "vite": "^5.4.8" + } +} diff --git a/substrate/frame/revive/rpc/examples/js/pvm/event.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/event.polkavm new file mode 100644 index 000000000000..859c1cdf5d3e Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/event.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..1a45c15d53f6 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/pvm/revert.polkavm b/substrate/frame/revive/rpc/examples/js/pvm/revert.polkavm new file mode 100644 index 000000000000..7505c402f21b Binary files /dev/null and b/substrate/frame/revive/rpc/examples/js/pvm/revert.polkavm differ 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..c6b7700d1ccf --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/build-contracts.ts @@ -0,0 +1,56 @@ +import { compile } from '@parity/revive' +import solc from 'solc' +import { readFileSync, writeFileSync } from 'fs' +import { join } from 'path' + +type CompileInput = Parameters[0] +type CompileOutput = Awaited> +type Abi = CompileOutput['contracts'][string][string]['abi'] + +function evmCompile(sources: CompileInput) { + const input = { + language: 'Solidity', + sources, + settings: { + outputSelection: { + '*': { + '*': ['*'], + }, + }, + }, + } + + return solc.compile(JSON.stringify(input)) +} + +console.log('Compiling contracts...') + +const input = [ + { file: 'Event.sol', contract: 'EventExample', keypath: 'event' }, + { file: 'Revert.sol', contract: 'RevertExample', keypath: 'revert' }, + { file: 'PiggyBank.sol', contract: 'PiggyBank', keypath: 'piggyBank' }, +] + +for (const { keypath, contract, file } of input) { + const input = { + [file]: { content: readFileSync(join('contracts', file), 'utf8') }, + } + + { + console.log(`Compile with solc ${file}`) + const out = JSON.parse(evmCompile(input)) + const entry = out.contracts[file][contract] + writeFileSync(join('evm', `${keypath}.bin`), Buffer.from(entry.evm.bytecode.object, 'hex')) + writeFileSync(join('abi', `${keypath}.json`), JSON.stringify(entry.abi, null, 2)) + } + + { + console.log(`Compile with revive ${file}`) + const out = await compile(input) + const entry = out.contracts[file][contract] + writeFileSync( + join('pvm', `${keypath}.polkavm`), + Buffer.from(entry.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..94cc2560272e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/event.ts @@ -0,0 +1,15 @@ +//! Run with bun run script-event.ts +import { call, getContract, deploy } from './lib.ts' + +try { + const { abi, bytecode } = getContract('event') + const contract = await deploy(bytecode, abi) + const receipt = await call('triggerEvent', await contract.getAddress(), abi) + if (receipt) { + for (const log of receipt.logs) { + console.log('Event log:', JSON.stringify(log, null, 2)) + } + } +} catch (err) { + console.error(err) +} 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..975d8faf15b3 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/lib.ts @@ -0,0 +1,110 @@ +import { + Contract, + ContractFactory, + JsonRpcProvider, + TransactionReceipt, + TransactionResponse, + Wallet, +} from 'ethers' +import { readFileSync } from 'node:fs' +import type { compile } from '@parity/revive' +import { spawn } from 'node:child_process' +import { parseArgs } from 'node:util' +import { BaseContract } from 'ethers' + +type CompileOutput = Awaited> +type Abi = CompileOutput['contracts'][string][string]['abi'] + +const { + values: { geth, westend, ['private-key']: privateKey }, +} = parseArgs({ + args: process.argv.slice(2), + options: { + ['private-key']: { + type: 'string', + short: 'k', + }, + 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', + '8546', + '--dev', + '--verbosity', + '0', + ], + { stdio: 'inherit' } + ) + + process.on('exit', () => child.kill()) + child.unref() + await new Promise((resolve) => setTimeout(resolve, 500)) +} + +export const provider = new JsonRpcProvider( + westend + ? 'https://westend-asset-hub-eth-rpc.polkadot.io' + : geth + ? 'http://localhost:8546' + : 'http://localhost:8545' +) + +export const signer = privateKey ? new Wallet(privateKey, provider) : await provider.getSigner() +console.log(`Signer address: ${await signer.getAddress()}, Nonce: ${await signer.getNonce()}`) + +/** + * Get one of the pre-built contracts + * @param name - the contract name + */ +export function getContract(name: string): { abi: Abi; bytecode: string } { + const bytecode = geth ? readFileSync(`evm/${name}.bin`) : readFileSync(`pvm/${name}.polkavm`) + const abi = JSON.parse(readFileSync(`abi/${name}.json`, 'utf8')) as Abi + return { abi, bytecode: Buffer.from(bytecode).toString('hex') } +} + +/** + * Deploy a contract + * @returns the contract address + **/ +export async function deploy(bytecode: string, abi: Abi, args: any[] = []): Promise { + console.log('Deploying contract with', args) + const contractFactory = new ContractFactory(abi, bytecode, signer) + + const contract = await contractFactory.deploy(args) + await contract.waitForDeployment() + const address = await contract.getAddress() + console.log(`Contract deployed: ${address}`) + + return contract +} + +/** + * Call a contract + **/ +export async function call( + method: string, + address: string, + abi: Abi, + args: any[] = [], + opts: { value?: bigint } = {} +): Promise { + console.log(`Calling ${method} at ${address} with`, args, opts) + const contract = new Contract(address, abi, signer) + const tx = (await contract[method](...args, opts)) as TransactionResponse + console.log('Call transaction hash:', tx.hash) + return tx.wait() +} 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..7a8edbde3662 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/piggy-bank.ts @@ -0,0 +1,24 @@ +import { provider, call, getContract, deploy } from './lib.ts' +import { parseEther } from 'ethers' +import { PiggyBank } from '../types/ethers-contracts/PiggyBank' + +try { + const { abi, bytecode } = getContract('piggyBank') + const contract = (await deploy(bytecode, abi)) as PiggyBank + const address = await contract.getAddress() + + let receipt = await call('deposit', address, abi, [], { + value: parseEther('10.0'), + }) + console.log('Deposit receipt:', receipt?.status) + console.log(`Contract balance: ${await provider.getBalance(address)}`) + + console.log('deposit: ', await contract.getDeposit()) + + receipt = await call('withdraw', address, abi, [parseEther('5.0')]) + console.log('Withdraw receipt:', receipt?.status) + console.log(`Contract balance: ${await provider.getBalance(address)}`) + console.log('deposit: ', await contract.getDeposit()) +} catch (err) { + console.error(err) +} diff --git a/substrate/frame/revive/rpc/examples/js/src/revert.ts b/substrate/frame/revive/rpc/examples/js/src/revert.ts new file mode 100644 index 000000000000..ea1bf4eceeb9 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/revert.ts @@ -0,0 +1,10 @@ +//! Run with bun run script-revert.ts +import { call, getContract, deploy } from './lib.ts' + +try { + const { abi, bytecode } = getContract('revert') + const contract = await deploy(bytecode, abi) + await call('doRevert', await contract.getAddress(), abi) +} catch (err) { + console.error(err) +} 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..ae2dd50f2af8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/src/transfer.ts @@ -0,0 +1,17 @@ +import { parseEther } from 'ethers' +import { provider, signer } from './lib.ts' + +const recipient = '0x75E480dB528101a381Ce68544611C169Ad7EB342' +try { + console.log(`Signer balance: ${await provider.getBalance(signer.address)}`) + console.log(`Recipient balance: ${await provider.getBalance(recipient)}`) + await signer.sendTransaction({ + to: recipient, + value: parseEther('1.0'), + }) + console.log(`Sent: ${parseEther('1.0')}`) + console.log(`Signer balance: ${await provider.getBalance(signer.address)}`) + console.log(`Recipient balance: ${await provider.getBalance(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 new file mode 100644 index 000000000000..55cb8379e886 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/tsconfig.json @@ -0,0 +1,23 @@ +{ + "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, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Event.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Event.ts new file mode 100644 index 000000000000..d65f953969f0 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Event.ts @@ -0,0 +1,117 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumberish, + BytesLike, + FunctionFragment, + Result, + Interface, + EventFragment, + AddressLike, + ContractRunner, + ContractMethod, + Listener, +} from 'ethers' +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedLogDescription, + TypedListener, + TypedContractMethod, +} from './common' + +export interface EventInterface extends Interface { + getFunction(nameOrSignature: 'triggerEvent'): FunctionFragment + + getEvent(nameOrSignatureOrTopic: 'ExampleEvent'): EventFragment + + encodeFunctionData(functionFragment: 'triggerEvent', values?: undefined): string + + decodeFunctionResult(functionFragment: 'triggerEvent', data: BytesLike): Result +} + +export namespace ExampleEventEvent { + export type InputTuple = [sender: AddressLike, value: BigNumberish, message: string] + export type OutputTuple = [sender: string, value: bigint, message: string] + export interface OutputObject { + sender: string + value: bigint + message: string + } + export type Event = TypedContractEvent + export type Filter = TypedDeferredTopicFilter + export type Log = TypedEventLog + export type LogDescription = TypedLogDescription +} + +export interface Event extends BaseContract { + connect(runner?: ContractRunner | null): Event + waitForDeployment(): Promise + + interface: EventInterface + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + + on( + event: TCEvent, + listener: TypedListener + ): Promise + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + once( + event: TCEvent, + listener: TypedListener + ): Promise + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + listeners( + event: TCEvent + ): Promise>> + listeners(eventName?: string): Promise> + removeAllListeners(event?: TCEvent): Promise + + triggerEvent: TypedContractMethod<[], [void], 'nonpayable'> + + getFunction(key: string | FunctionFragment): T + + getFunction(nameOrSignature: 'triggerEvent'): TypedContractMethod<[], [void], 'nonpayable'> + + getEvent( + key: 'ExampleEvent' + ): TypedContractEvent< + ExampleEventEvent.InputTuple, + ExampleEventEvent.OutputTuple, + ExampleEventEvent.OutputObject + > + + filters: { + 'ExampleEvent(address,uint256,string)': TypedContractEvent< + ExampleEventEvent.InputTuple, + ExampleEventEvent.OutputTuple, + ExampleEventEvent.OutputObject + > + ExampleEvent: TypedContractEvent< + ExampleEventEvent.InputTuple, + ExampleEventEvent.OutputTuple, + ExampleEventEvent.OutputObject + > + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/PiggyBank.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/PiggyBank.ts new file mode 100644 index 000000000000..ca137fcc8b30 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/PiggyBank.ts @@ -0,0 +1,96 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumberish, + BytesLike, + FunctionFragment, + Result, + Interface, + ContractRunner, + ContractMethod, + Listener, +} from 'ethers' +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedListener, + TypedContractMethod, +} from './common' + +export interface PiggyBankInterface extends Interface { + getFunction(nameOrSignature: 'deposit' | 'getDeposit' | 'owner' | 'withdraw'): FunctionFragment + + encodeFunctionData(functionFragment: 'deposit', values?: undefined): string + encodeFunctionData(functionFragment: 'getDeposit', values?: undefined): string + encodeFunctionData(functionFragment: 'owner', values?: undefined): string + encodeFunctionData(functionFragment: 'withdraw', values: [BigNumberish]): string + + decodeFunctionResult(functionFragment: 'deposit', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'getDeposit', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'owner', data: BytesLike): Result + decodeFunctionResult(functionFragment: 'withdraw', data: BytesLike): Result +} + +export interface PiggyBank extends BaseContract { + connect(runner?: ContractRunner | null): PiggyBank + waitForDeployment(): Promise + + interface: PiggyBankInterface + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + + on( + event: TCEvent, + listener: TypedListener + ): Promise + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + once( + event: TCEvent, + listener: TypedListener + ): Promise + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + listeners( + event: TCEvent + ): Promise>> + listeners(eventName?: string): Promise> + removeAllListeners(event?: TCEvent): Promise + + deposit: TypedContractMethod<[], [bigint], 'payable'> + + getDeposit: TypedContractMethod<[], [bigint], 'view'> + + owner: TypedContractMethod<[], [string], 'view'> + + withdraw: TypedContractMethod<[withdrawAmount: BigNumberish], [bigint], 'nonpayable'> + + getFunction(key: string | FunctionFragment): T + + getFunction(nameOrSignature: 'deposit'): TypedContractMethod<[], [bigint], 'payable'> + getFunction(nameOrSignature: 'getDeposit'): TypedContractMethod<[], [bigint], 'view'> + getFunction(nameOrSignature: 'owner'): TypedContractMethod<[], [string], 'view'> + getFunction( + nameOrSignature: 'withdraw' + ): TypedContractMethod<[withdrawAmount: BigNumberish], [bigint], 'nonpayable'> + + filters: {} +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Revert.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Revert.ts new file mode 100644 index 000000000000..ad6e23b38a65 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/Revert.ts @@ -0,0 +1,78 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BytesLike, + FunctionFragment, + Result, + Interface, + ContractRunner, + ContractMethod, + Listener, +} from 'ethers' +import type { + TypedContractEvent, + TypedDeferredTopicFilter, + TypedEventLog, + TypedListener, + TypedContractMethod, +} from './common' + +export interface RevertInterface extends Interface { + getFunction(nameOrSignature: 'doRevert'): FunctionFragment + + encodeFunctionData(functionFragment: 'doRevert', values?: undefined): string + + decodeFunctionResult(functionFragment: 'doRevert', data: BytesLike): Result +} + +export interface Revert extends BaseContract { + connect(runner?: ContractRunner | null): Revert + waitForDeployment(): Promise + + interface: RevertInterface + + queryFilter( + event: TCEvent, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + queryFilter( + filter: TypedDeferredTopicFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>> + + on( + event: TCEvent, + listener: TypedListener + ): Promise + on( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + once( + event: TCEvent, + listener: TypedListener + ): Promise + once( + filter: TypedDeferredTopicFilter, + listener: TypedListener + ): Promise + + listeners( + event: TCEvent + ): Promise>> + listeners(eventName?: string): Promise> + removeAllListeners(event?: TCEvent): Promise + + doRevert: TypedContractMethod<[], [void], 'nonpayable'> + + getFunction(key: string | FunctionFragment): T + + getFunction(nameOrSignature: 'doRevert'): TypedContractMethod<[], [void], 'nonpayable'> + + filters: {} +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/common.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/common.ts new file mode 100644 index 000000000000..247b9468ece2 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/common.ts @@ -0,0 +1,100 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + FunctionFragment, + Typed, + EventFragment, + ContractTransaction, + ContractTransactionResponse, + DeferredTopicFilter, + EventLog, + TransactionRequest, + LogDescription, +} from 'ethers' + +export interface TypedDeferredTopicFilter<_TCEvent extends TypedContractEvent> + extends DeferredTopicFilter {} + +export interface TypedContractEvent< + InputTuple extends Array = any, + OutputTuple extends Array = any, + OutputObject = any, +> { + ( + ...args: Partial + ): TypedDeferredTopicFilter> + name: string + fragment: EventFragment + getFragment(...args: Partial): EventFragment +} + +type __TypechainAOutputTuple = T extends TypedContractEvent ? W : never +type __TypechainOutputObject = + T extends TypedContractEvent ? V : never + +export interface TypedEventLog extends Omit { + args: __TypechainAOutputTuple & __TypechainOutputObject +} + +export interface TypedLogDescription + extends Omit { + args: __TypechainAOutputTuple & __TypechainOutputObject +} + +export type TypedListener = ( + ...listenerArg: [...__TypechainAOutputTuple, TypedEventLog, ...undefined[]] +) => void + +export type MinEthersFactory = { + deploy(...a: ARGS[]): Promise +} + +export type GetContractTypeFromFactory = F extends MinEthersFactory ? C : never +export type GetARGsTypeFromFactory = + F extends MinEthersFactory ? Parameters : never + +export type StateMutability = 'nonpayable' | 'payable' | 'view' + +export type BaseOverrides = Omit +export type NonPayableOverrides = Omit +export type PayableOverrides = Omit +export type ViewOverrides = Omit +export type Overrides = S extends 'nonpayable' + ? NonPayableOverrides + : S extends 'payable' + ? PayableOverrides + : ViewOverrides + +export type PostfixOverrides, S extends StateMutability> = + | A + | [...A, Overrides] +export type ContractMethodArgs, S extends StateMutability> = PostfixOverrides< + { [I in keyof A]-?: A[I] | Typed }, + S +> + +export type DefaultReturnType = R extends Array ? R[0] : R + +// export interface ContractMethod = Array, R = any, D extends R | ContractTransactionResponse = R | ContractTransactionResponse> { +export interface TypedContractMethod< + A extends Array = Array, + R = any, + S extends StateMutability = 'payable', +> { + ( + ...args: ContractMethodArgs + ): S extends 'view' ? Promise> : Promise + + name: string + + fragment: FunctionFragment + + getFragment(...args: ContractMethodArgs): FunctionFragment + + populateTransaction(...args: ContractMethodArgs): Promise + staticCall(...args: ContractMethodArgs): Promise> + send(...args: ContractMethodArgs): Promise + estimateGas(...args: ContractMethodArgs): Promise + staticCallResult(...args: ContractMethodArgs): Promise +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Event__factory.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Event__factory.ts new file mode 100644 index 000000000000..2e16b18a7ed8 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Event__factory.ts @@ -0,0 +1,51 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Interface, type ContractRunner } from 'ethers' +import type { Event, EventInterface } from '../Event' + +const _abi = [ + { + 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 + +export class Event__factory { + static readonly abi = _abi + static createInterface(): EventInterface { + return new Interface(_abi) as EventInterface + } + static connect(address: string, runner?: ContractRunner | null): Event { + return new Contract(address, _abi, runner) as unknown as Event + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/PiggyBank__factory.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/PiggyBank__factory.ts new file mode 100644 index 000000000000..0efea80ed2dc --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/PiggyBank__factory.ts @@ -0,0 +1,82 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Interface, type ContractRunner } from 'ethers' +import type { PiggyBank, PiggyBankInterface } from '../PiggyBank' + +const _abi = [ + { + 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 + +export class PiggyBank__factory { + static readonly abi = _abi + static createInterface(): PiggyBankInterface { + return new Interface(_abi) as PiggyBankInterface + } + static connect(address: string, runner?: ContractRunner | null): PiggyBank { + return new Contract(address, _abi, runner) as unknown as PiggyBank + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Revert__factory.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Revert__factory.ts new file mode 100644 index 000000000000..ece1c6b5426e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/Revert__factory.ts @@ -0,0 +1,31 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Interface, type ContractRunner } from 'ethers' +import type { Revert, RevertInterface } from '../Revert' + +const _abi = [ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [], + name: 'doRevert', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const + +export class Revert__factory { + static readonly abi = _abi + static createInterface(): RevertInterface { + return new Interface(_abi) as RevertInterface + } + static connect(address: string, runner?: ContractRunner | null): Revert { + return new Contract(address, _abi, runner) as unknown as Revert + } +} diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/index.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/index.ts new file mode 100644 index 000000000000..67370dba411c --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/factories/index.ts @@ -0,0 +1,6 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export { Event__factory } from './Event__factory' +export { PiggyBank__factory } from './PiggyBank__factory' +export { Revert__factory } from './Revert__factory' diff --git a/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/index.ts b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/index.ts new file mode 100644 index 000000000000..3e324e80dcb1 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/js/types/ethers-contracts/index.ts @@ -0,0 +1,10 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export type { Event } from './Event' +export type { PiggyBank } from './PiggyBank' +export type { Revert } from './Revert' +export * as factories from './factories' +export { Event__factory } from './factories/Event__factory' +export { PiggyBank__factory } from './factories/PiggyBank__factory' +export { Revert__factory } from './factories/Revert__factory' diff --git a/substrate/frame/revive/rpc/examples/rpc_demo.polkavm b/substrate/frame/revive/rpc/examples/rpc_demo.polkavm new file mode 120000 index 000000000000..63925dfcc544 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rpc_demo.polkavm @@ -0,0 +1 @@ +../../../../../target/pallet-revive-fixtures/rpc_demo.polkavm \ No newline at end of file diff --git a/substrate/frame/revive/rpc/examples/rust/deploy.rs b/substrate/frame/revive/rpc/examples/rust/deploy.rs new file mode 100644 index 000000000000..b74d7ea18d41 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/deploy.rs @@ -0,0 +1,78 @@ +// 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 jsonrpsee::http_client::HttpClientBuilder; +use pallet_revive::{ + create1, + evm::{Account, BlockTag, ReceiptInfo, U256}, +}; +use pallet_revive_eth_rpc::{ + example::{wait_for_receipt, TransactionBuilder}, + EthRpcClient, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + env_logger::init(); + let account = Account::default(); + + let data = vec![]; + let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; + let input = bytes.into_iter().chain(data.clone()).collect::>(); + + println!("Account:"); + println!("- address: {:?}", account.address()); + println!("- substrate: {}", account.substrate_account()); + let client = HttpClientBuilder::default().build("http://localhost:8545")?; + + println!("\n\n=== Deploying contract ===\n\n"); + + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).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, .. } = + wait_for_receipt(&client, hash).await?; + + let contract_address = contract_address.unwrap(); + assert_eq!(contract_address, create1(&account.address(), nonce.try_into().unwrap())); + + println!("Receipt:"); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- Contract address: {contract_address:?}"); + let balance = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + println!("- Contract balance: {balance:?}"); + + println!("\n\n=== Calling contract ===\n\n"); + 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?; + println!("Receipt:"); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- To: {to:?}"); + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs new file mode 100644 index 000000000000..e15743e2385e --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/extrinsic.rs @@ -0,0 +1,54 @@ +// 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 pallet_revive_eth_rpc::subxt_client::{ + self, revive::calls::types::InstantiateWithCode, SrcChainConfig, +}; +use sp_weights::Weight; +use subxt::OnlineClient; +use subxt_signer::sr25519::dev; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = OnlineClient::::new().await?; + + let (bytes, _) = pallet_revive_fixtures::compile_module("dummy")?; + + let tx_payload = subxt_client::tx().revive().instantiate_with_code( + 0u32.into(), + Weight::from_parts(100_000, 0).into(), + 3_000_000_000_000_000_000, + bytes, + vec![], + None, + ); + + let res = client + .tx() + .sign_and_submit_then_watch_default(&tx_payload, &dev::alice()) + .await? + .wait_for_finalized() + .await?; + println!("Transaction finalized: {:?}", res.extrinsic_hash()); + + let block_hash = res.block_hash(); + + let block = client.blocks().at(block_hash).await.unwrap(); + let extrinsics = block.extrinsics().await.unwrap(); + let _ = extrinsics.find_first::()?; + + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs new file mode 100644 index 000000000000..b106d27c218a --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/remark-extrinsic.rs @@ -0,0 +1,43 @@ +// 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 pallet_revive_eth_rpc::subxt_client::{self, system::calls::types::Remark, SrcChainConfig}; +use subxt::OnlineClient; +use subxt_signer::sr25519::dev; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = OnlineClient::::new().await?; + let tx_payload = subxt_client::tx().system().remark(b"bonjour".to_vec()); + let res = client + .tx() + .sign_and_submit_then_watch_default(&tx_payload, &dev::alice()) + .await? + .wait_for_finalized() + .await?; + + println!("Transaction finalized: {:?}", res.extrinsic_hash()); + let block_hash = res.block_hash(); + let block = client.blocks().at(block_hash).await.unwrap(); + let extrinsics = block.extrinsics().await.unwrap(); + let remarks = extrinsics + .find::() + .map(|remark| remark.unwrap().value) + .collect::>(); + + dbg!(remarks); + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs b/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs new file mode 100644 index 000000000000..64175ca60b5f --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/rpc-playground.rs @@ -0,0 +1,41 @@ +// 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 jsonrpsee::http_client::HttpClientBuilder; +use pallet_revive::evm::{Account, BlockTag}; +use pallet_revive_eth_rpc::EthRpcClient; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let account = Account::default(); + println!("Account address: {:?}", account.address()); + + let client = HttpClientBuilder::default().build("http://localhost:8545")?; + + let block = client.get_block_by_number(BlockTag::Latest.into(), false).await?; + println!("Latest block: {block:#?}"); + + let nonce = client.get_transaction_count(account.address(), BlockTag::Latest.into()).await?; + println!("Account nonce: {nonce:?}"); + + let balance = client.get_balance(account.address(), BlockTag::Latest.into()).await?; + println!("Account balance: {balance:?}"); + + let sync_state = client.syncing().await?; + println!("Sync state: {sync_state:?}"); + + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/rust/transfer.rs b/substrate/frame/revive/rpc/examples/rust/transfer.rs new file mode 100644 index 000000000000..1d67a2dba28f --- /dev/null +++ b/substrate/frame/revive/rpc/examples/rust/transfer.rs @@ -0,0 +1,61 @@ +// 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 jsonrpsee::http_client::HttpClientBuilder; +use pallet_revive::evm::{Account, BlockTag, ReceiptInfo}; +use pallet_revive_eth_rpc::{ + example::{wait_for_receipt, TransactionBuilder}, + EthRpcClient, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + 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(ethan.address(), BlockTag::Latest.into()).await?; + println!("ethan {:?} balance: {balance:?}", ethan.address()); + anyhow::Result::<()>::Ok(()) + }; + + print_balance().await?; + println!("\n\n=== Transferring ===\n\n"); + + 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, .. } = + wait_for_receipt(&client, hash).await?; + println!("Receipt: "); + println!("- Block number: {block_number}"); + println!("- Gas used: {gas_used}"); + println!("- Success: {status:?}"); + + print_balance().await?; + Ok(()) +} diff --git a/substrate/frame/revive/rpc/examples/westend_local_network.toml b/substrate/frame/revive/rpc/examples/westend_local_network.toml new file mode 100644 index 000000000000..28295db76133 --- /dev/null +++ b/substrate/frame/revive/rpc/examples/westend_local_network.toml @@ -0,0 +1,41 @@ +[settings] +node_spawn_timeout = 240 + +[relaychain] +default_command = "{{POLKADOT_BINARY}}" +default_args = ["-lparachain=debug,xcm=trace"] +chain = "westend-local" +[[relaychain.nodes]] +name = "alice-westend-validator" +validator = true +rpc_port = 9935 +ws_port = 9945 +balance = 2000000000000 + +[[relaychain.nodes]] +name = "bob-westend-validator" +validator = true +rpc_port = 9936 +ws_port = 9946 +balance = 2000000000000 + +[[parachains]] +id = 1000 +chain = "asset-hub-westend-local" +cumulus_based = true + +[[parachains.collators]] +name = "asset-hub-westend-collator1" +rpc_port = 9011 +ws_port = 9944 +command = "{{POLKADOT_PARACHAIN_BINARY}}" +args = [ + "-lparachain=debug,runtime::revive=debug", +] + +[[parachains.collators]] +name = "asset-hub-westend-collator2" +command = "{{POLKADOT_PARACHAIN_BINARY}}" +args = [ + "-lparachain=debug,runtime::revive=debug", +] diff --git a/substrate/frame/revive/rpc/revive_chain.metadata b/substrate/frame/revive/rpc/revive_chain.metadata new file mode 100644 index 000000000000..3560b3b90407 Binary files /dev/null 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 new file mode 100644 index 000000000000..c0f81fcafd77 --- /dev/null +++ b/substrate/frame/revive/rpc/src/cli.rs @@ -0,0 +1,161 @@ +// 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. +//! The Ethereum JSON-RPC server. +use crate::{ + client::Client, EthRpcServer, EthRpcServerImpl, SystemHealthRpcServer, + SystemHealthRpcServerImpl, +}; +use clap::Parser; +use futures::{pin_mut, FutureExt}; +use jsonrpsee::server::RpcModule; +use sc_cli::{PrometheusParams, RpcParams, SharedParams, Signals}; +use sc_service::{ + config::{PrometheusConfig, RpcConfiguration}, + start_rpc_servers, TaskManager, +}; + +// Default port if --prometheus-port is not specified +const DEFAULT_PROMETHEUS_PORT: u16 = 9616; + +// Default port if --rpc-port is not specified +const DEFAULT_RPC_PORT: u16 = 8545; + +// Parsed command instructions from the command line +#[derive(Parser, Debug)] +#[clap(author, about, version)] +pub struct CliCommand { + /// The node url to connect to + #[clap(long, default_value = "ws://127.0.0.1:9944")] + pub node_rpc_url: String, + + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub rpc_params: RpcParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub prometheus_params: PrometheusParams, +} + +/// Initialize the logger +#[cfg(not(test))] +fn init_logger(params: &SharedParams) -> anyhow::Result<()> { + let mut logger = sc_cli::LoggerBuilder::new(params.log_filters().join(",")); + logger + .with_log_reloading(params.enable_log_reloading) + .with_detailed_output(params.detailed_log_output); + + if let Some(tracing_targets) = ¶ms.tracing_targets { + let tracing_receiver = params.tracing_receiver.into(); + logger.with_profiling(tracing_receiver, tracing_targets); + } + + if params.disable_log_color { + logger.with_colors(false); + } + + logger.init()?; + Ok(()) +} + +/// Start the JSON-RPC server using the given command line arguments. +pub fn run(cmd: CliCommand) -> anyhow::Result<()> { + let CliCommand { rpc_params, prometheus_params, node_rpc_url, shared_params, .. } = cmd; + + #[cfg(not(test))] + init_logger(&shared_params)?; + let is_dev = shared_params.dev; + let rpc_addrs: Option> = rpc_params + .rpc_addr(is_dev, false, 8545)? + .map(|addrs| addrs.into_iter().map(Into::into).collect()); + + let rpc_config = RpcConfiguration { + addr: rpc_addrs, + methods: rpc_params.rpc_methods.into(), + max_connections: rpc_params.rpc_max_connections, + cors: rpc_params.rpc_cors(is_dev)?, + max_request_size: rpc_params.rpc_max_request_size, + max_response_size: rpc_params.rpc_max_response_size, + id_provider: None, + max_subs_per_conn: rpc_params.rpc_max_subscriptions_per_connection, + port: rpc_params.rpc_port.unwrap_or(DEFAULT_RPC_PORT), + message_buffer_capacity: rpc_params.rpc_message_buffer_capacity_per_connection, + batch_config: rpc_params.rpc_batch_config()?, + rate_limit: rpc_params.rpc_rate_limit, + rate_limit_whitelisted_ips: rpc_params.rpc_rate_limit_whitelisted_ips, + rate_limit_trust_proxy_headers: rpc_params.rpc_rate_limit_trust_proxy_headers, + }; + + let prometheus_config = + prometheus_params.prometheus_config(DEFAULT_PROMETHEUS_PORT, "eth-rpc".into()); + let prometheus_registry = prometheus_config.as_ref().map(|config| &config.registry); + + let tokio_runtime = sc_cli::build_runtime()?; + let tokio_handle = tokio_runtime.handle(); + let signals = tokio_runtime.block_on(async { Signals::capture() })?; + let mut task_manager = TaskManager::new(tokio_handle.clone(), prometheus_registry)?; + let essential_spawn_handle = task_manager.spawn_essential_handle(); + + let gen_rpc_module = || { + let signals = tokio_runtime.block_on(async { Signals::capture() })?; + let fut = Client::from_url(&node_rpc_url, &essential_spawn_handle).fuse(); + pin_mut!(fut); + + match tokio_handle.block_on(signals.try_until_signal(fut)) { + Ok(Ok(client)) => rpc_module(is_dev, client), + 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())), + } + }; + + // Prometheus metrics. + if let Some(PrometheusConfig { port, registry }) = prometheus_config.clone() { + task_manager.spawn_handle().spawn( + "prometheus-endpoint", + None, + prometheus_endpoint::init_prometheus(port, registry).map(drop), + ); + } + + let rpc_server_handle = + start_rpc_servers(&rpc_config, prometheus_registry, tokio_handle, gen_rpc_module, None)?; + + task_manager.keep_alive(rpc_server_handle); + tokio_runtime.block_on(signals.run_until_signal(task_manager.future().fuse()))?; + Ok(()) +} + +/// Create the JSON-RPC module. +fn rpc_module(is_dev: bool, client: Client) -> Result, sc_service::Error> { + 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 new file mode 100644 index 000000000000..1ca1a6d37c53 --- /dev/null +++ b/substrate/frame/revive/rpc/src/client.rs @@ -0,0 +1,822 @@ +// 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. +//! 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, events::ContractEmitted}, + runtime_types::pallet_revive::storage::ContractInfo, + }, + TransactionLegacySigned, LOG_TARGET, +}; +use futures::{stream, StreamExt}; +use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObjectOwned}; +use pallet_revive::{ + create1, + evm::{ + Block, BlockNumberOrTag, BlockNumberOrTagOrHash, Bytes256, GenericTransaction, Log, + ReceiptInfo, SyncingProgress, SyncingStatus, TransactionSigned, H160, H256, U256, + }, + EthContractResult, +}; +use sp_core::keccak_256; +use sp_weights::Weight; +use std::{ + collections::{HashMap, VecDeque}, + sync::Arc, + time::Duration, +}; +use subxt::{ + backend::{ + legacy::{rpc_methods::SystemHealth, LegacyRpcMethods}, + rpc::{ + reconnecting_rpc_client::{ExponentialBackoff, RpcClient as ReconnectingRpcClient}, + RpcClient, + }, + }, + config::Header, + error::RpcError, + storage::Storage, + Config, OnlineClient, +}; +use subxt_client::transaction_payment::events::TransactionFeePaid; +use thiserror::Error; +use tokio::sync::{watch::Sender, RwLock}; + +use crate::subxt_client::{self, system::events::ExtrinsicSuccess, SrcChainConfig}; + +/// The substrate block type. +pub type SubstrateBlock = subxt::blocks::Block>; + +/// The substrate block number type. +pub type SubstrateBlockNumber = <::Header as Header>::Number; + +/// The substrate block hash type. +pub type SubstrateBlockHash = ::Hash; + +/// Type alias for shared data. +pub type Shared = Arc>; + +/// The runtime balance type. +pub type Balance = u128; + +/// The cache maintains a buffer of the last N blocks, +#[derive(Default)] +struct BlockCache { + /// A double-ended queue of the last N blocks. + /// The most recent block is at the back of the queue, and the oldest block is at the front. + buffer: VecDeque>, + + /// A map of blocks by block number. + blocks_by_number: HashMap>, + + /// A map of blocks by block hash. + blocks_by_hash: HashMap>, + + /// A map of receipts by hash. + receipts_by_hash: HashMap, + + /// A map of Signed transaction by hash. + signed_tx_by_hash: HashMap, + + /// A map of receipt hashes by block hash. + tx_hashes_by_block_and_index: HashMap>, +} + +/// 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::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, + } +} + +/// Extract the revert message from a revert("msg") solidity statement. +fn extract_revert_message(exec_data: &[u8]) -> Option { + let function_selector = exec_data.get(0..4)?; + + // keccak256("Error(string)") + let expected_selector = [0x08, 0xC3, 0x79, 0xA0]; + if function_selector != expected_selector { + return None; + } + + let decoded = ethabi::decode(&[ethabi::ParamType::String], &exec_data[4..]).ok()?; + match decoded.first()? { + ethabi::Token::String(msg) => Some(msg.to_string()), + _ => None, + } +} + +/// 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(transparent)] + SubxtError(#[from] subxt::Error), + /// A [`RpcError`] wrapper error. + #[error(transparent)] + RpcError(#[from] RpcError), + /// A [`codec::Error`] wrapper error. + #[error(transparent)] + CodecError(#[from] codec::Error), + /// The dry run failed. + #[error("Dry run failed: {0}")] + DryRunFailed(String), + /// Contract reverted + #[error("Execution reverted: {}", extract_revert_message(.0).unwrap_or_default())] + Reverted(Vec), + /// A decimal conversion failed. + #[error("Conversion failed")] + ConversionFailed, + /// The block hash was not found. + #[error("Hash not found")] + BlockNotFound, + /// The transaction fee could not be found + #[error("TransactionFeePaid event not found")] + TxFeeNotFound, + /// The cache is empty. + #[error("Cache is empty")] + CacheEmpty, +} + +// TODO convert error code to https://eips.ethereum.org/EIPS/eip-1474#error-codes +impl From for ErrorObjectOwned { + fn from(err: ClientError) -> Self { + let msg = err.to_string(); + 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, msg, None) + }, + ClientError::Reverted(data) => { + let data = format!("0x{}", hex::encode(data)); + ErrorObjectOwned::owned::(CALL_EXECUTION_FAILED_CODE, msg, Some(data)) + }, + _ => ErrorObjectOwned::owned::(CALL_EXECUTION_FAILED_CODE, msg, None), + } + } +} + +/// The number of recent blocks maintained by the cache. +/// For each block in the cache, we also store the EVM transaction receipts. +pub const CACHE_SIZE: usize = 256; + +impl BlockCache { + fn latest_block(&self) -> Option<&Arc> { + self.buffer.back() + } + + /// Insert an entry into the cache, and prune the oldest entry if the cache is full. + fn insert(&mut self, block: SubstrateBlock) { + if self.buffer.len() >= N { + if let Some(block) = self.buffer.pop_front() { + log::trace!(target: LOG_TARGET, "Pruning block: {}", block.number()); + let hash = block.hash(); + self.blocks_by_hash.remove(&hash); + self.blocks_by_number.remove(&block.number()); + if let Some(entries) = self.tx_hashes_by_block_and_index.remove(&hash) { + for hash in entries.values() { + self.receipts_by_hash.remove(hash); + } + } + } + } + + let block = Arc::new(block); + self.buffer.push_back(block.clone()); + self.blocks_by_number.insert(block.number(), block.clone()); + self.blocks_by_hash.insert(block.hash(), block); + } +} + +/// 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, + /// A watch channel to signal cache updates. + pub updates: tokio::sync::watch::Receiver<()>, +} + +/// The inner state of the client. +struct ClientInner { + api: OnlineClient, + rpc_client: ReconnectingRpcClient, + rpc: LegacyRpcMethods, + cache: Shared>, + chain_id: u64, + max_block_weight: Weight, +} + +impl ClientInner { + /// Create a new client instance connecting to the substrate node at the given URL. + async fn from_url(url: &str) -> Result { + let rpc_client = ReconnectingRpcClient::builder() + .retry_policy(ExponentialBackoff::from_millis(100).max_delay(Duration::from_secs(10))) + .build(url.to_string()) + .await?; + + let api = OnlineClient::::from_rpc_client(rpc_client.clone()).await?; + let cache = Arc::new(RwLock::new(BlockCache::::default())); + + let rpc = LegacyRpcMethods::::new(RpcClient::new(rpc_client.clone())); + + 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 }) + } + + /// Get the receipt infos from the extrinsics in a block. + async fn receipt_infos( + &self, + block: &SubstrateBlock, + ) -> Result, ClientError> { + // Get extrinsics from the block + let extrinsics = block.extrinsics().await?; + + // Filter extrinsics from pallet_revive + let extrinsics = extrinsics.iter().flat_map(|ext| { + let call = ext.as_extrinsic::().ok()??; + let transaction_hash = H256(keccak_256(&call.payload)); + 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()?)) + } else { + None + }; + + Some((from, tx, transaction_hash, contract_address, ext)) + }); + + // Map each extrinsic to a receipt + stream::iter(extrinsics) + .map(|(from, tx, 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_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 block_hash = block.hash(); + let block_number = block.number().into(); + + // 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, + logs, + tx.transaction_legacy_unsigned.to, + gas_price, + gas_used.into(), + success, + transaction_hash, + transaction_index.into(), + tx.transaction_legacy_unsigned.r#type.as_byte() + ); + + Ok::<_, ClientError>((receipt.transaction_hash, (tx.into(), receipt))) + }) + .buffer_unordered(10) + .collect::>>() + .await + .into_iter() + .collect::, _>>() + } +} + +/// Fetch the chain ID from the substrate chain. +async fn chain_id(api: &OnlineClient) -> Result { + let query = subxt_client::constants().revive().chain_id(); + api.constants().at(&query).map_err(|err| err.into()) +} + +/// Fetch the max block weight from the substrate chain. +async fn max_block_weight(api: &OnlineClient) -> Result { + let query = subxt_client::constants().system().block_weights(); + let weights = api.constants().at(&query)?; + let max_block = weights.per_class.normal.max_extrinsic.unwrap_or(weights.max_block); + Ok(max_block.0) +} + +/// Extract the block timestamp. +async fn extract_block_timestamp(block: &SubstrateBlock) -> Option { + let extrinsics = block.extrinsics().await.ok()?; + let ext = extrinsics + .find_first::() + .ok()??; + + Some(ext.value.now / 1000) +} + +impl Client { + /// Create a new client instance. + /// The client will subscribe to new blocks and maintain a cache of [`CACHE_SIZE`] blocks. + pub async fn from_url( + url: &str, + spawn_handle: &sc_service::SpawnEssentialTaskHandle, + ) -> Result { + log::info!(target: LOG_TARGET, "Connecting to node at: {url} ..."); + let inner: Arc = Arc::new(ClientInner::from_url(url).await?); + log::info!(target: LOG_TARGET, "Connected to node at: {url}"); + + let (tx, mut updates) = tokio::sync::watch::channel(()); + + spawn_handle.spawn("subscribe-blocks", None, Self::subscribe_blocks(inner.clone(), tx)); + + updates.changed().await.expect("tx is not dropped"); + Ok(Self { inner, updates }) + } + + /// Expose the storage API. + async fn storage_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result>, ClientError> { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.storage().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.storage().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.storage().at(block.hash())); + } + let storage = self.inner.api.storage().at_latest().await?; + Ok(storage) + }, + } + } + + /// Expose the runtime API. + async fn runtime_api( + &self, + at: &BlockNumberOrTagOrHash, + ) -> Result< + subxt::runtime_api::RuntimeApi>, + ClientError, + > { + match at { + BlockNumberOrTagOrHash::U256(block_number) => { + let n: SubstrateBlockNumber = + (*block_number).try_into().map_err(|_| ClientError::ConversionFailed)?; + + let hash = self.get_block_hash(n).await?.ok_or(ClientError::BlockNotFound)?; + Ok(self.inner.api.runtime_api().at(hash)) + }, + BlockNumberOrTagOrHash::H256(hash) => Ok(self.inner.api.runtime_api().at(*hash)), + BlockNumberOrTagOrHash::BlockTag(_) => { + if let Some(block) = self.latest_block().await { + return Ok(self.inner.api.runtime_api().at(block.hash())); + } + + let api = self.inner.api.runtime_api().at_latest().await?; + Ok(api) + }, + } + } + + /// 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"); + let mut block_stream = match inner.as_ref().api.blocks().subscribe_best().await { + Ok(s) => s, + Err(err) => { + log::error!(target: LOG_TARGET, "Failed to subscribe to blocks: {err:?}"); + return; + }, + }; + + while let Some(block) = block_stream.next().await { + let block = match block { + Ok(block) => block, + Err(err) => { + if err.is_disconnected_will_reconnect() { + log::warn!( + target: LOG_TARGET, + "The RPC connection was lost and we may have missed a few blocks" + ); + continue; + } + + log::error!(target: LOG_TARGET, "Failed to fetch block: {err:?}"); + return; + }, + }; + + log::trace!(target: LOG_TARGET, "Pushing block: {}", block.number()); + let mut cache = inner.cache.write().await; + + let receipts = inner + .receipt_infos(&block) + .await + .inspect_err(|err| { + log::error!(target: LOG_TARGET, "Failed to get receipts: {err:?}"); + }) + .unwrap_or_default(); + + if !receipts.is_empty() { + let values = receipts + .iter() + .map(|(hash, (_, receipt))| (receipt.transaction_index, *hash)) + .collect::>(); + + cache.tx_hashes_by_block_and_index.insert(block.hash(), values); + + cache + .receipts_by_hash + .extend(receipts.iter().map(|(hash, (_, receipt))| (*hash, receipt.clone()))); + + cache.signed_tx_by_hash.extend( + receipts.iter().map(|(hash, (signed_tx, _))| (*hash, signed_tx.clone())), + ) + } + + cache.insert(block); + tx.send_replace(()); + } + + log::info!(target: LOG_TARGET, "Block subscription ended"); + } +} + +impl Client { + /// Get the most recent block stored in the cache. + pub async fn latest_block(&self) -> Option> { + let cache = self.inner.cache.read().await; + let block = cache.latest_block()?; + Some(block.clone()) + } + + /// Expose the transaction API. + pub async fn submit( + &self, + call: subxt::tx::DefaultPayload, + ) -> Result { + let ext = self.inner.api.tx().create_unsigned(&call).map_err(ClientError::from)?; + let hash = ext.submit().await?; + Ok(hash) + } + + /// Get an EVM transaction receipt by hash. + pub async fn receipt(&self, tx_hash: &H256) -> Option { + let cache = self.inner.cache.read().await; + cache.receipts_by_hash.get(tx_hash).cloned() + } + + /// Get the syncing status of the chain. + pub async fn syncing(&self) -> Result { + let health = self.inner.rpc.system_health().await?; + + let status = if health.is_syncing { + let client = RpcClient::new(self.inner.rpc_client.clone()); + let sync_state: sc_rpc::system::SyncState = + client.request("system_syncState", Default::default()).await?; + + SyncingProgress { + current_block: Some(sync_state.current_block.into()), + highest_block: Some(sync_state.highest_block.into()), + starting_block: Some(sync_state.starting_block.into()), + } + .into() + } else { + SyncingStatus::Bool(false) + }; + + Ok(status) + } + + /// Get an EVM transaction receipt by hash. + pub async fn receipt_by_hash_and_index( + &self, + block_hash: &H256, + transaction_index: &U256, + ) -> Option { + let cache = self.inner.cache.read().await; + let receipt_hash = + cache.tx_hashes_by_block_and_index.get(block_hash)?.get(transaction_index)?; + let receipt = cache.receipts_by_hash.get(receipt_hash)?; + Some(receipt.clone()) + } + + pub async fn signed_tx_by_hash(&self, tx_hash: &H256) -> Option { + let cache = self.inner.cache.read().await; + cache.signed_tx_by_hash.get(tx_hash).cloned() + } + + /// Get receipts count per block. + pub async fn receipts_count_per_block(&self, block_hash: &SubstrateBlockHash) -> Option { + let cache = self.inner.cache.read().await; + 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, + address: H160, + at: &BlockNumberOrTagOrHash, + ) -> Result { + // TODO: remove once subxt is updated + let address = address.0.into(); + + let runtime_api = self.runtime_api(at).await?; + let payload = subxt_client::apis().revive_api().balance(address); + let balance = runtime_api.call(payload).await?; + + Ok(*balance) + } + + /// Get the contract storage for the given contract address and key. + pub async fn get_contract_storage( + &self, + contract_address: H160, + key: U256, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let runtime_api = self.runtime_api(&block).await?; + + // TODO: remove once subxt is updated + let contract_address = contract_address.0.into(); + + let payload = subxt_client::apis() + .revive_api() + .get_storage(contract_address, key.to_big_endian()); + let result = runtime_api.call(payload).await?.unwrap_or_default().unwrap_or_default(); + Ok(result) + } + + /// Get the contract code for the given contract address. + pub async fn get_contract_code( + &self, + contract_address: &H160, + block: BlockNumberOrTagOrHash, + ) -> Result, ClientError> { + let storage_api = self.storage_api(&block).await?; + + // TODO: remove once subxt is updated + let contract_address: subxt::utils::H160 = contract_address.0.into(); + + let query = subxt_client::storage().revive().contract_info_of(contract_address); + let Some(ContractInfo { code_hash, .. }) = storage_api.fetch(&query).await? else { + return Ok(Vec::new()); + }; + + let query = subxt_client::storage().revive().pristine_code(code_hash); + let result = storage_api.fetch(&query).await?.map(|v| v.0).unwrap_or_default(); + Ok(result) + } + + /// Dry run a transaction and returns the [`EthContractResult`] for the transaction. + pub async fn dry_run( + &self, + tx: &GenericTransaction, + block: BlockNumberOrTagOrHash, + ) -> Result>, ClientError> { + let runtime_api = self.runtime_api(&block).await?; + + // TODO: remove once subxt is updated + let value = subxt::utils::Static(tx.value.unwrap_or_default()); + 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 EthContractResult { fee, gas_required, storage_deposit, result } = + runtime_api.call(payload).await?.0; + match result { + Err(err) => { + log::debug!(target: LOG_TARGET, "Dry run failed {err:?}"); + Err(ClientError::DryRunFailed(format!("{err:?}"))) + }, + Ok(result) if result.did_revert() => { + log::debug!(target: LOG_TARGET, "Dry run reverted"); + Err(ClientError::Reverted(result.0.data)) + }, + Ok(result) => + Ok(EthContractResult { fee, gas_required, storage_deposit, result: result.0.data }), + } + } + + /// 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) + } + + /// Get the nonce of the given address. + pub async fn nonce( + &self, + address: H160, + at: BlockNumberOrTagOrHash, + ) -> Result { + let address = address.0.into(); + + let runtime_api = self.runtime_api(&at).await?; + let payload = subxt_client::apis().revive_api().nonce(address); + let nonce = runtime_api.call(payload).await?; + Ok(nonce.into()) + } + + /// Get the block number of the latest block. + pub async fn block_number(&self) -> Result { + let cache = self.inner.cache.read().await; + let latest_block = cache.buffer.back().ok_or(ClientError::CacheEmpty)?; + Ok(latest_block.number()) + } + + /// Get a block hash for the given block number. + pub async fn get_block_hash( + &self, + block_number: SubstrateBlockNumber, + ) -> Result, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_number.get(&block_number) { + return Ok(Some(block.hash())); + } + + let hash = self.inner.rpc.chain_get_block_hash(Some(block_number.into())).await?; + Ok(hash) + } + + /// Get a block for the specified hash or number. + pub async fn block_by_number_or_tag( + &self, + block: &BlockNumberOrTag, + ) -> Result>, ClientError> { + match block { + BlockNumberOrTag::U256(n) => { + let n = (*n).try_into().map_err(|_| ClientError::ConversionFailed)?; + self.block_by_number(n).await + }, + BlockNumberOrTag::BlockTag(_) => { + let cache = self.inner.cache.read().await; + Ok(cache.buffer.back().cloned()) + }, + } + } + + /// Get a block by hash + pub async fn block_by_hash( + &self, + hash: &SubstrateBlockHash, + ) -> Result>, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_hash.get(hash) { + return Ok(Some(block.clone())); + } + + match self.inner.api.blocks().at(*hash).await { + Ok(block) => Ok(Some(Arc::new(block))), + Err(subxt::Error::Block(subxt::error::BlockError::NotFound(_))) => Ok(None), + Err(err) => Err(err.into()), + } + } + + /// Get a block by number + pub async fn block_by_number( + &self, + block_number: SubstrateBlockNumber, + ) -> Result>, ClientError> { + let cache = self.inner.cache.read().await; + if let Some(block) = cache.blocks_by_number.get(&block_number) { + return Ok(Some(block.clone())); + } + + let Some(hash) = self.get_block_hash(block_number).await? else { + return Ok(None); + }; + + self.block_by_hash(&hash).await + } + + /// Get the EVM block for the given hash. + pub async fn evm_block(&self, block: Arc) -> Result { + let runtime_api = self.inner.api.runtime_api().at(block.hash()); + let max_fee = Self::weight_to_fee(&runtime_api, self.max_block_weight()).await?; + let gas_limit = U256::from(max_fee / GAS_PRICE as u128); + + let header = block.header(); + let timestamp = extract_block_timestamp(&block).await.unwrap_or_default(); + + // TODO: remove once subxt is updated + let parent_hash = header.parent_hash.0.into(); + let state_root = header.state_root.0.into(); + let extrinsics_root = header.extrinsics_root.0.into(); + + Ok(Block { + hash: block.hash(), + parent_hash, + state_root, + transactions_root: extrinsics_root, + number: header.number.into(), + timestamp: timestamp.into(), + difficulty: Some(0u32.into()), + gas_limit, + logs_bloom: Bytes256([0u8; 256]), + receipts_root: extrinsics_root, + ..Default::default() + }) + } + + /// Convert a weight to a fee. + async fn weight_to_fee( + runtime_api: &subxt::runtime_api::RuntimeApi>, + weight: Weight, + ) -> Result { + let payload = subxt_client::apis() + .transaction_payment_api() + .query_weight_to_fee(weight.into()); + + let fee = runtime_api.call(payload).await?; + Ok(fee) + } + + /// Get the chain ID. + pub fn chain_id(&self) -> u64 { + self.inner.chain_id + } + + /// Get the Max Block Weight. + pub fn max_block_weight(&self) -> Weight { + self.inner.max_block_weight + } +} diff --git a/substrate/frame/revive/rpc/src/example.rs b/substrate/frame/revive/rpc/src/example.rs new file mode 100644 index 000000000000..20f00465b146 --- /dev/null +++ b/substrate/frame/revive/rpc/src/example.rs @@ -0,0 +1,191 @@ +// 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. +//! Example utilities +#![cfg(any(feature = "example", test))] + +use crate::{EthRpcClient, ReceiptInfo}; +use anyhow::Context; +use pallet_revive::evm::{ + rlp::*, Account, BlockTag, Bytes, GenericTransaction, TransactionLegacyUnsigned, H160, H256, + U256, +}; + +/// Wait for a transaction receipt. +pub async fn wait_for_receipt( + client: &(impl EthRpcClient + Send + Sync), + hash: H256, +) -> anyhow::Result { + for _ in 0..30 { + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + let receipt = client.get_transaction_receipt(hash).await?; + if let Some(receipt) = receipt { + return Ok(receipt) + } + } + + anyhow::bail!("Failed to get receipt") +} + +/// 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, + 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.clone()); + let bytes = tx.rlp_bytes().to_vec(); + + let hash = client + .send_raw_transaction(bytes.clone().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 new file mode 100644 index 000000000000..8d9d6fab829e --- /dev/null +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -0,0 +1,361 @@ +// 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. +//! The [`EthRpcServer`] RPC server implementation +#![cfg_attr(docsrs, feature(doc_cfg))] + +use crate::runtime::GAS_PRICE; +use client::ClientError; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::{ErrorCode, ErrorObjectOwned}, +}; +use pallet_revive::{evm::*, EthContractResult}; +use sp_core::{keccak_256, H160, H256, U256}; +use thiserror::Error; + +pub mod cli; +pub mod client; +pub mod example; +pub mod subxt_client; + +#[cfg(test)] +mod tests; + +mod rpc_health; +pub use rpc_health::*; + +mod rpc_methods_gen; +pub use rpc_methods_gen::*; + +pub const LOG_TARGET: &str = "eth-rpc"; + +/// An EVM RPC server implementation. +pub struct EthRpcServerImpl { + /// The client used to interact with the substrate node. + client: client::Client, + + /// The accounts managed by the server. + accounts: Vec, +} + +impl EthRpcServerImpl { + /// Creates a new [`EthRpcServerImpl`]. + pub fn new(client: client::Client) -> Self { + Self { client, accounts: vec![] } + } + + /// Sets the accounts managed by the server. + pub fn with_accounts(mut self, accounts: Vec) -> Self { + self.accounts = accounts; + self + } +} + +/// The error type for the EVM RPC server. +#[derive(Error, Debug)] +pub enum EthRpcError { + /// A [`ClientError`] wrapper error. + #[error("Client error: {0}")] + ClientError(#[from] ClientError), + /// A [`rlp::DecoderError`] wrapper error. + #[error("Decoding error: {0}")] + RlpError(#[from] rlp::DecoderError), + /// A Decimals conversion error. + #[error("Conversion error")] + ConversionError, + /// An invalid signature error. + #[error("Invalid signature")] + InvalidSignature, + /// The account was not found at the given address + #[error("Account not found for address {0:?}")] + AccountNotFound(H160), + /// Received an invalid transaction + #[error("Invalid transaction")] + InvalidTransaction, + /// Received an invalid transaction + #[error("Invalid transaction {0:?}")] + TransactionTypeNotSupported(Byte), +} + +// TODO use https://eips.ethereum.org/EIPS/eip-1474#error-codes +impl From for ErrorObjectOwned { + fn from(value: EthRpcError) -> Self { + match value { + EthRpcError::ClientError(err) => Self::from(err), + _ => Self::owned::(ErrorCode::InvalidRequest.code(), value.to_string(), None), + } + } +} + +#[async_trait] +impl EthRpcServer for EthRpcServerImpl { + async fn net_version(&self) -> RpcResult { + Ok(self.client.chain_id().to_string()) + } + + async fn syncing(&self) -> RpcResult { + Ok(self.client.syncing().await?) + } + + async fn block_number(&self) -> RpcResult { + let number = self.client.block_number().await?; + Ok(number.into()) + } + + async fn get_transaction_receipt( + &self, + 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, + ) -> RpcResult { + let result = self.client.estimate_gas(&transaction, BlockTag::Latest.into()).await?; + Ok(result) + } + + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult { + let hash = H256(keccak_256(&transaction.0)); + + let tx = rlp::decode::(&transaction.0).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); + EthRpcError::from(err) + })?; + + let eth_addr = tx.recover_eth_address().map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to recover eth address: {err:?}"); + EthRpcError::InvalidSignature + })?; + + // 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 EthContractResult { gas_required, storage_deposit, .. } = dry_run; + let call = subxt_client::tx().revive().eth_transact( + transaction.0, + gas_required.into(), + storage_deposit, + ); + self.client.submit(call).await?; + log::debug!(target: LOG_TARGET, "send_raw_transaction hash: {hash:?}"); + Ok(hash) + } + + async fn send_transaction(&self, 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 { + log::debug!(target: LOG_TARGET, "Transaction must have a sender"); + return Err(EthRpcError::InvalidTransaction.into()); + }; + + let account = self + .accounts + .iter() + .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(); + + let Some(gas) = gas else { + log::debug!(target: LOG_TARGET, "Transaction must have a gas limit"); + return Err(EthRpcError::InvalidTransaction.into()); + }; + + let r#type = Type0::try_from_byte(r#type.clone()) + .map_err(|_| EthRpcError::TransactionTypeNotSupported(r#type))?; + + let nonce = self.get_transaction_count(from, BlockTag::Latest.into()).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 + } + + async fn get_block_by_hash( + &self, + block_hash: H256, + _hydrated_transactions: bool, + ) -> RpcResult> { + let Some(block) = self.client.block_by_hash(&block_hash).await? else { + return Ok(None); + }; + let block = self.client.evm_block(block).await?; + Ok(Some(block)) + } + + async fn get_balance(&self, address: H160, block: BlockNumberOrTagOrHash) -> RpcResult { + let balance = self.client.balance(address, &block).await?; + log::debug!(target: LOG_TARGET, "balance({address}): {balance:?}"); + Ok(balance) + } + + async fn chain_id(&self) -> RpcResult { + Ok(self.client.chain_id().into()) + } + + async fn gas_price(&self) -> RpcResult { + Ok(U256::from(GAS_PRICE)) + } + + async fn get_code(&self, address: H160, block: BlockNumberOrTagOrHash) -> RpcResult { + let code = self.client.get_contract_code(&address, block).await?; + Ok(code.into()) + } + + async fn accounts(&self) -> RpcResult> { + 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?; + Ok(dry_run.result.into()) + } + + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + _hydrated_transactions: bool, + ) -> RpcResult> { + let Some(block) = self.client.block_by_number_or_tag(&block).await? else { + return Ok(None); + }; + let block = self.client.evm_block(block).await?; + Ok(Some(block)) + } + + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult> { + let block_hash = if let Some(block_hash) = block_hash { + block_hash + } else { + self.client.latest_block().await.ok_or(ClientError::BlockNotFound)?.hash() + }; + Ok(self.client.receipts_count_per_block(&block_hash).await.map(U256::from)) + } + + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult> { + let Some(block) = self + .get_block_by_number(block.unwrap_or_else(|| BlockTag::Latest.into()), false) + .await? + else { + return Ok(None); + }; + + Ok(self.client.receipts_count_per_block(&block.hash).await.map(U256::from)) + } + + async fn get_storage_at( + &self, + address: H160, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let bytes = self.client.get_contract_storage(address, storage_slot, block).await?; + Ok(bytes.into()) + } + + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult> { + let Some(receipt) = + self.client.receipt_by_hash_and_index(&block_hash, &transaction_index).await + else { + return Ok(None); + }; + + let Some(signed_tx) = self.client.signed_tx_by_hash(&receipt.transaction_hash).await else { + return Ok(None); + }; + + Ok(Some(TransactionInfo::new(receipt, signed_tx))) + } + + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult> { + let Some(block) = self.client.block_by_number_or_tag(&block).await? else { + return Ok(None); + }; + self.get_transaction_by_block_hash_and_index(block.hash(), transaction_index) + .await + } + + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult> { + let receipt = self.client.receipt(&transaction_hash).await; + let signed_tx = self.client.signed_tx_by_hash(&transaction_hash).await; + if let (Some(receipt), Some(signed_tx)) = (receipt, signed_tx) { + return Ok(Some(TransactionInfo::new(receipt, signed_tx))); + } + + Ok(None) + } + + async fn get_transaction_count( + &self, + address: H160, + block: BlockNumberOrTagOrHash, + ) -> RpcResult { + let nonce = self.client.nonce(address, block).await?; + Ok(nonce) + } +} diff --git a/substrate/frame/revive/rpc/src/main.rs b/substrate/frame/revive/rpc/src/main.rs new file mode 100644 index 000000000000..3376b9b10be2 --- /dev/null +++ b/substrate/frame/revive/rpc/src/main.rs @@ -0,0 +1,24 @@ +// 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. +//! The Ethereum JSON-RPC server. +use clap::Parser; +use pallet_revive_eth_rpc::cli; + +fn main() -> anyhow::Result<()> { + let cmd = cli::CliCommand::parse(); + cli::run(cmd) +} 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 new file mode 100644 index 000000000000..339080368969 --- /dev/null +++ b/substrate/frame/revive/rpc/src/rpc_methods_gen.rs @@ -0,0 +1,160 @@ +// 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. +//! Generated JSON-RPC methods. +#![allow(missing_docs)] + +use super::*; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +#[rpc(server, client)] +pub trait EthRpc { + /// Returns a list of addresses owned by client. + #[method(name = "eth_accounts")] + async fn accounts(&self) -> RpcResult>; + + /// Returns the number of most recent block. + #[method(name = "eth_blockNumber")] + async fn block_number(&self) -> RpcResult; + + /// Executes a new message call immediately without creating a transaction on the block chain. + #[method(name = "eth_call")] + async fn call( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the chain ID of the current network. + #[method(name = "eth_chainId")] + async fn chain_id(&self) -> RpcResult; + + /// Generates and returns an estimate of how much gas is necessary to allow the transaction to + /// complete. + #[method(name = "eth_estimateGas")] + async fn estimate_gas( + &self, + transaction: GenericTransaction, + block: Option, + ) -> RpcResult; + + /// Returns the current price per gas in wei. + #[method(name = "eth_gasPrice")] + async fn gas_price(&self) -> RpcResult; + + /// Returns the balance of the account of given address. + #[method(name = "eth_getBalance")] + async fn get_balance(&self, address: Address, block: BlockNumberOrTagOrHash) + -> RpcResult; + + /// Returns information about a block by hash. + #[method(name = "eth_getBlockByHash")] + async fn get_block_by_hash( + &self, + block_hash: H256, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns information about a block by number. + #[method(name = "eth_getBlockByNumber")] + async fn get_block_by_number( + &self, + block: BlockNumberOrTag, + hydrated_transactions: bool, + ) -> RpcResult>; + + /// Returns the number of transactions in a block from a block matching the given block hash. + #[method(name = "eth_getBlockTransactionCountByHash")] + async fn get_block_transaction_count_by_hash( + &self, + block_hash: Option, + ) -> RpcResult>; + + /// Returns the number of transactions in a block matching the given block number. + #[method(name = "eth_getBlockTransactionCountByNumber")] + async fn get_block_transaction_count_by_number( + &self, + block: Option, + ) -> RpcResult>; + + /// Returns code at a given address. + #[method(name = "eth_getCode")] + async fn get_code(&self, address: Address, block: BlockNumberOrTagOrHash) -> RpcResult; + + /// Returns the value from a storage position at a given address. + #[method(name = "eth_getStorageAt")] + async fn get_storage_at( + &self, + address: Address, + storage_slot: U256, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns information about a transaction by block hash and transaction index position. + #[method(name = "eth_getTransactionByBlockHashAndIndex")] + async fn get_transaction_by_block_hash_and_index( + &self, + block_hash: H256, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns information about a transaction by block number and transaction index position. + #[method(name = "eth_getTransactionByBlockNumberAndIndex")] + async fn get_transaction_by_block_number_and_index( + &self, + block: BlockNumberOrTag, + transaction_index: U256, + ) -> RpcResult>; + + /// Returns the information about a transaction requested by transaction hash. + #[method(name = "eth_getTransactionByHash")] + async fn get_transaction_by_hash( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Returns the number of transactions sent from an address. + #[method(name = "eth_getTransactionCount")] + async fn get_transaction_count( + &self, + address: Address, + block: BlockNumberOrTagOrHash, + ) -> RpcResult; + + /// Returns the receipt of a transaction by transaction hash. + #[method(name = "eth_getTransactionReceipt")] + async fn get_transaction_receipt( + &self, + transaction_hash: H256, + ) -> RpcResult>; + + /// Submits a raw transaction. For EIP-4844 transactions, the raw form must be the network form. + /// This means it includes the blobs, KZG commitments, and KZG proofs. + #[method(name = "eth_sendRawTransaction")] + async fn send_raw_transaction(&self, transaction: Bytes) -> RpcResult; + + /// Signs and submits a transaction. + #[method(name = "eth_sendTransaction")] + async fn send_transaction(&self, transaction: GenericTransaction) -> RpcResult; + + /// Returns an object with data about the sync status or false. + #[method(name = "eth_syncing")] + async fn syncing(&self) -> RpcResult; + + /// The string value of current network id + #[method(name = "net_version")] + async fn net_version(&self) -> RpcResult; +} diff --git a/substrate/frame/revive/rpc/src/subxt_client.rs b/substrate/frame/revive/rpc/src/subxt_client.rs new file mode 100644 index 000000000000..a232b231bc7c --- /dev/null +++ b/substrate/frame/revive/rpc/src/subxt_client.rs @@ -0,0 +1,80 @@ +// 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. +//! The generated subxt client. +//! Generated against a substrate chain configured with [`pallet_revive`] using: +//! subxt metadata --url ws://localhost:9944 -o rpc/revive_chain.scale +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 = "primitive_types::U256", + with = "::subxt::utils::Static<::sp_core::U256>" + ), + substitute_type( + path = "pallet_revive::primitives::EthContractResult", + with = "::subxt::utils::Static<::pallet_revive::EthContractResult>" + ), + substitute_type( + path = "pallet_revive::primitives::ExecReturnValue", + with = "::subxt::utils::Static<::pallet_revive::ExecReturnValue>" + ), + substitute_type( + path = "sp_weights::weight_v2::Weight", + with = "::subxt::utils::Static<::sp_weights::Weight>" + ) +)] +mod src_chain {} +pub use src_chain::*; + +/// The configuration for the source chain. +pub enum SrcChainConfig {} +impl Config for SrcChainConfig { + type Hash = sp_core::H256; + type AccountId = ::AccountId; + type Address = ::Address; + type Signature = ::Signature; + type Hasher = BlakeTwo256; + type Header = subxt::config::substrate::SubstrateHeader; + type AssetId = ::AssetId; + type ExtrinsicParams = signed_extensions::AnyOf< + Self, + ( + signed_extensions::CheckSpecVersion, + signed_extensions::CheckTxVersion, + signed_extensions::CheckNonce, + signed_extensions::CheckGenesis, + signed_extensions::CheckMortality, + signed_extensions::ChargeAssetTxPayment, + signed_extensions::ChargeTransactionPayment, + signed_extensions::CheckMetadataHash, + ), + >; +} + +/// A type that can hash values using the blaks2_256 algorithm. +/// TODO remove once subxt is updated +#[derive(Debug, Clone, Copy, PartialEq, Eq, codec::Encode)] +pub struct BlakeTwo256; + +impl subxt::config::Hasher for BlakeTwo256 { + type Output = sp_core::H256; + fn hash(s: &[u8]) -> Self::Output { + sp_crypto_hashing::blake2_256(s).into() + } +} diff --git a/substrate/frame/revive/rpc/src/tests.rs b/substrate/frame/revive/rpc/src/tests.rs new file mode 100644 index 000000000000..eb23bd7583a0 --- /dev/null +++ b/substrate/frame/revive/rpc/src/tests.rs @@ -0,0 +1,321 @@ +// 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. +//! Test the eth-rpc cli with the kitchensink node. + +use crate::{ + cli::{self, CliCommand}, + 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, U256}, +}; +use static_init::dynamic; +use std::thread; +use substrate_cli_test_utils::*; + +/// Create a websocket client with a 30s timeout. +async fn ws_client_with_retry(url: &str) -> WsClient { + let timeout = tokio::time::Duration::from_secs(30); + tokio::time::timeout(timeout, async { + loop { + if let Ok(client) = WsClientBuilder::default().build(url).await { + return client + } else { + tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + } + } + }) + .await + .expect("Hit timeout") +} + +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=45788", + "--node-rpc-url=ws://localhost:45789", + "--no-prometheus", + "-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"), + } + } +); + +#[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 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 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(); + let value = U256::from(5_000_000_000_000u128); + 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 = 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), + receipt.contract_address, + "Contract should be deployed with the correct address." + ); + + let balance = client.get_balance(contract_address, BlockTag::Latest.into()).await?; + assert_eq!(value, balance, "Contract balance should be the same as the value sent."); + + // Call contract + 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("revert")?; + let receipt = TransactionBuilder::default() + .input(contract.constructor.clone().unwrap().encode_input(bytecode, &[]).unwrap()) + .send_and_wait_for_receipt(&client) + .await?; + + let err = TransactionBuilder::default() + .to(receipt.contract_address.unwrap()) + .input(contract.function("doRevert")?.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: revert message"); + Ok(()) +} + +#[tokio::test] +async fn event_logs() -> anyhow::Result<()> { + let _lock = SHARED_RESOURCES.write(); + let client = SharedResources::client().await; + let (bytecode, contract) = get_contract("event")?; + 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/address.rs b/substrate/frame/revive/src/address.rs index c51940ba771e..45b5bf822dc9 100644 --- a/substrate/frame/revive/src/address.rs +++ b/substrate/frame/revive/src/address.rs @@ -17,61 +17,173 @@ //! Functions that deal contract addresses. +use crate::{ensure, AddressSuffix, Config, Error, HoldReason}; use alloc::vec::Vec; -use sp_core::H160; +use core::marker::PhantomData; +use frame_support::traits::{fungible::MutateHold, tokens::Precision}; +use sp_core::{Get, H160}; use sp_io::hashing::keccak_256; -use sp_runtime::AccountId32; +use sp_runtime::{AccountId32, DispatchResult, SaturatedConversion, Saturating}; /// Map between the native chain account id `T` and an Ethereum [`H160`]. /// /// This trait exists only to emulate specialization for different concrete /// native account ids. **Not** to make the mapping user configurable. Hence -/// the trait is `Sealed` and only one mandatory implementor [`DefaultAddressMapper`] -/// exists. +/// the trait is `Sealed` and depending on your runtime configuration you need +/// to pick either [`AccountId32Mapper`] or [`H160Mapper`]. Picking the wrong +/// one will result in a compilation error. No footguns here. /// /// Please note that we assume that the native account is at least 20 bytes and /// only implement this type for a `T` where this is the case. Luckily, this is the -/// case for all existing runtimes as of right now. Reasing is that this will allow +/// case for all existing runtimes as of right now. Reasoning is that this will allow /// us to reverse an address -> account_id mapping by just stripping the prefix. -pub trait AddressMapper: private::Sealed { +/// +/// We require the mapping to be reversible. Since we are potentially dealing with types of +/// different sizes one direction of the mapping is necessarily lossy. This requires the mapping to +/// make use of the [`AddressSuffix`] storage item to reverse the mapping. +pub trait AddressMapper: private::Sealed { /// Convert an account id to an ethereum adress. - /// - /// This mapping is **not** required to be reversible. - fn to_address(account_id: &T) -> H160; + fn to_address(account_id: &T::AccountId) -> H160; /// Convert an ethereum address to a native account id. + fn to_account_id(address: &H160) -> T::AccountId; + + /// Same as [`Self::to_account_id`] but always returns the fallback account. + /// + /// This skips the query into [`AddressSuffix`] and always returns the stateless + /// fallback account. This is useful when we know for a fact that the `address` + /// in question is originally a `H160`. This is usually only the case when we + /// generated a new contract address. + fn to_fallback_account_id(address: &H160) -> T::AccountId; + + /// Create a stateful mapping for `account_id` + /// + /// This will enable `to_account_id` to map back to the original + /// `account_id` instead of the fallback account id. + fn map(account_id: &T::AccountId) -> DispatchResult; + + /// Remove the mapping in order to reclaim the deposit. /// - /// This mapping is **required** to be reversible. - fn to_account_id(address: &H160) -> T; + /// There is no reason why one would unmap their `account_id` except + /// for reclaiming the deposit. + fn unmap(account_id: &T::AccountId) -> DispatchResult; - /// Same as [`Self::to_account_id`] but when we know the address is a contract. + /// Returns true if the `account_id` is useable as an origin. /// - /// This is only the case when we just generated the new address. - fn to_account_id_contract(address: &H160) -> T; + /// This means either the `account_id` doesn't require a stateful mapping + /// or a stateful mapping exists. + fn is_mapped(account_id: &T::AccountId) -> bool; } mod private { pub trait Sealed {} - impl Sealed for super::DefaultAddressMapper {} + impl Sealed for super::AccountId32Mapper {} + impl Sealed for super::H160Mapper {} } -/// The only implementor for `AddressMapper`. -pub enum DefaultAddressMapper {} +/// The mapper to be used if the account id is `AccountId32`. +/// +/// It converts between addresses by either truncating the last 12 bytes or +/// suffixing them. The suffix is queried from [`AddressSuffix`] and will fall +/// back to all `0xEE` if no suffix was registered. This means contracts and +/// plain wallets controlled by an `secp256k1` always have a `0xEE` suffixed +/// account. +pub struct AccountId32Mapper(PhantomData); + +/// The mapper to be used if the account id is `H160`. +/// +/// It just trivially returns its inputs and doesn't make use of any state. +pub struct H160Mapper(PhantomData); -impl AddressMapper for DefaultAddressMapper { +impl AddressMapper for AccountId32Mapper +where + T: Config, +{ fn to_address(account_id: &AccountId32) -> H160 { H160::from_slice(&>::as_ref(&account_id)[..20]) } fn to_account_id(address: &H160) -> AccountId32 { + if let Some(suffix) = >::get(address) { + let mut account_id = Self::to_fallback_account_id(address); + let account_bytes: &mut [u8; 32] = account_id.as_mut(); + account_bytes[20..].copy_from_slice(suffix.as_slice()); + account_id + } else { + Self::to_fallback_account_id(address) + } + } + + fn to_fallback_account_id(address: &H160) -> AccountId32 { let mut account_id = AccountId32::new([0xEE; 32]); - >::as_mut(&mut account_id)[..20] - .copy_from_slice(address.as_bytes()); + let account_bytes: &mut [u8; 32] = account_id.as_mut(); + account_bytes[..20].copy_from_slice(address.as_bytes()); account_id } - fn to_account_id_contract(address: &H160) -> AccountId32 { - Self::to_account_id(address) + fn map(account_id: &T::AccountId) -> DispatchResult { + ensure!(!Self::is_mapped(account_id), >::AccountAlreadyMapped); + + let account_bytes: &[u8; 32] = account_id.as_ref(); + + // each mapping entry stores one AccountId32 distributed between key and value + let deposit = T::DepositPerByte::get() + .saturating_mul(account_bytes.len().saturated_into()) + .saturating_add(T::DepositPerItem::get()); + + let suffix: [u8; 12] = account_bytes[20..] + .try_into() + .expect("Skipping 20 byte of a an 32 byte array will fit into 12 bytes; qed"); + T::Currency::hold(&HoldReason::AddressMapping.into(), account_id, deposit)?; + >::insert(Self::to_address(account_id), suffix); + Ok(()) + } + + fn unmap(account_id: &T::AccountId) -> DispatchResult { + // will do nothing if address is not mapped so no check required + >::remove(Self::to_address(account_id)); + T::Currency::release_all( + &HoldReason::AddressMapping.into(), + account_id, + Precision::BestEffort, + )?; + Ok(()) + } + + fn is_mapped(account_id: &T::AccountId) -> bool { + let account_bytes: &[u8; 32] = account_id.as_ref(); + &account_bytes[20..] == &[0xEE; 12] || + >::contains_key(Self::to_address(account_id)) + } +} + +impl AddressMapper for H160Mapper +where + T: Config, + crate::AccountIdOf: AsRef<[u8; 20]> + From, +{ + fn to_address(account_id: &T::AccountId) -> H160 { + H160::from_slice(account_id.as_ref()) + } + + fn to_account_id(address: &H160) -> T::AccountId { + Self::to_fallback_account_id(address) + } + + fn to_fallback_account_id(address: &H160) -> T::AccountId { + (*address).into() + } + + fn map(_account_id: &T::AccountId) -> DispatchResult { + Ok(()) + } + + fn unmap(_account_id: &T::AccountId) -> DispatchResult { + Ok(()) + } + + fn is_mapped(_account_id: &T::AccountId) -> bool { + true } } @@ -102,7 +214,16 @@ pub fn create2(deployer: &H160, code: &[u8], input_data: &[u8], salt: &[u8; 32]) #[cfg(test)] mod test { use super::*; - use crate::test_utils::ALICE_ADDR; + use crate::{ + test_utils::*, + tests::{ExtBuilder, Test}, + AddressMapper, Error, + }; + use frame_support::{ + assert_err, + traits::fungible::{InspectHold, Mutate}, + }; + use pretty_assertions::assert_eq; use sp_core::{hex2array, H160}; #[test] @@ -125,4 +246,123 @@ mod test { H160(hex2array!("7f31e795e5836a19a8f919ab5a9de9a197ecd2b6")), ) } + + #[test] + fn fallback_map_works() { + assert!(::AddressMapper::is_mapped(&ALICE)); + assert_eq!( + ALICE_FALLBACK, + ::AddressMapper::to_fallback_account_id(&ALICE_ADDR) + ); + assert_eq!(ALICE_ADDR, ::AddressMapper::to_address(&ALICE_FALLBACK)); + } + + #[test] + fn map_works() { + ExtBuilder::default().build().execute_with(|| { + ::Currency::set_balance(&EVE, 1_000_000); + // before mapping the fallback account is returned + assert!(!::AddressMapper::is_mapped(&EVE)); + assert_eq!(EVE_FALLBACK, ::AddressMapper::to_account_id(&EVE_ADDR)); + assert_eq!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE + ), + 0 + ); + + // when mapped the full account id is returned + ::AddressMapper::map(&EVE).unwrap(); + assert!(::AddressMapper::is_mapped(&EVE)); + assert_eq!(EVE, ::AddressMapper::to_account_id(&EVE_ADDR)); + assert!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE + ) > 0 + ); + }); + } + + #[test] + fn map_fallback_account_fails() { + ExtBuilder::default().build().execute_with(|| { + assert!(::AddressMapper::is_mapped(&ALICE)); + // alice is an e suffixed account and hence cannot be mapped + assert_err!( + ::AddressMapper::map(&ALICE), + >::AccountAlreadyMapped, + ); + assert_eq!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &ALICE + ), + 0 + ); + }); + } + + #[test] + fn double_map_fails() { + ExtBuilder::default().build().execute_with(|| { + assert!(!::AddressMapper::is_mapped(&EVE)); + ::Currency::set_balance(&EVE, 1_000_000); + ::AddressMapper::map(&EVE).unwrap(); + assert!(::AddressMapper::is_mapped(&EVE)); + let deposit = ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE, + ); + assert_err!( + ::AddressMapper::map(&EVE), + >::AccountAlreadyMapped, + ); + assert!(::AddressMapper::is_mapped(&EVE)); + assert_eq!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE + ), + deposit + ); + }); + } + + #[test] + fn unmap_works() { + ExtBuilder::default().build().execute_with(|| { + ::Currency::set_balance(&EVE, 1_000_000); + ::AddressMapper::map(&EVE).unwrap(); + assert!(::AddressMapper::is_mapped(&EVE)); + assert!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE + ) > 0 + ); + + ::AddressMapper::unmap(&EVE).unwrap(); + assert!(!::AddressMapper::is_mapped(&EVE)); + assert_eq!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE + ), + 0 + ); + + // another unmap is a noop + ::AddressMapper::unmap(&EVE).unwrap(); + assert!(!::AddressMapper::is_mapped(&EVE)); + assert_eq!( + ::Currency::balance_on_hold( + &HoldReason::AddressMapping.into(), + &EVE + ), + 0 + ); + }); + } } diff --git a/substrate/frame/revive/src/benchmarking/call_builder.rs b/substrate/frame/revive/src/benchmarking/call_builder.rs index 8a859a3a5089..c666383abb2f 100644 --- a/substrate/frame/revive/src/benchmarking/call_builder.rs +++ b/substrate/frame/revive/src/benchmarking/call_builder.rs @@ -26,7 +26,7 @@ use crate::{ }; use alloc::{vec, vec::Vec}; use frame_benchmarking::benchmarking; -use sp_core::U256; +use sp_core::{H256, U256}; type StackExt<'a, T> = Stack<'a, T, WasmBlob>; @@ -48,6 +48,7 @@ where T: Config + pallet_balances::Config, BalanceOf: Into + TryFrom, MomentOf: Into, + T::Hash: frame_support::traits::IsType, { fn default() -> Self { Self::new(WasmModule::dummy()) @@ -59,6 +60,7 @@ where T: Config + pallet_balances::Config, BalanceOf: Into + TryFrom, MomentOf: Into, + T::Hash: frame_support::traits::IsType, { /// Setup a new call for the given module. pub fn new(module: WasmModule) -> Self { diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index ebafb6c7054a..9c4d817a07de 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -15,9 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Benchmarks for the contracts pallet +//! Benchmarks for the revive pallet -#![cfg(all(feature = "runtime-benchmarks", feature = "riscv"))] +#![cfg(feature = "runtime-benchmarks")] mod call_builder; mod code; @@ -63,6 +63,7 @@ const UNBALANCED_TRIE_LAYERS: u32 = 20; struct Contract { caller: T::AccountId, account_id: T::AccountId, + address: H160, } impl Contract @@ -70,12 +71,8 @@ where T: Config + pallet_balances::Config, BalanceOf: Into + TryFrom, MomentOf: Into, + T::Hash: frame_support::traits::IsType, { - /// Returns the address of the contract. - fn address(&self) -> H160 { - T::AddressMapper::to_address(&self.account_id) - } - /// Create new contract and use a default account id as instantiator. fn new(module: WasmModule, data: Vec) -> Result, &'static str> { Self::with_index(0, module, data) @@ -98,9 +95,12 @@ where ) -> Result, &'static str> { T::Currency::set_balance(&caller, caller_funding::()); let salt = Some([0xffu8; 32]); + let origin: T::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + + Contracts::::map_account(origin.clone()).unwrap(); let outcome = Contracts::::bare_instantiate( - RawOrigin::Signed(caller.clone()).into(), + origin, 0u32.into(), Weight::MAX, default_deposit_limit::(), @@ -112,8 +112,8 @@ where ); let address = outcome.result?.addr; - let account_id = T::AddressMapper::to_account_id_contract(&address); - let result = Contract { caller, account_id: account_id.clone() }; + let account_id = T::AddressMapper::to_fallback_account_id(&address); + let result = Contract { caller, address, account_id }; ContractInfoOf::::insert(&address, result.info()?); @@ -143,7 +143,7 @@ where info.write(&Key::Fix(item.0), Some(item.1.clone()), None, false) .map_err(|_| "Failed to write storage to restoration dest")?; } - >::insert(T::AddressMapper::to_address(&self.account_id), info); + >::insert(&self.address, info); Ok(()) } @@ -169,7 +169,7 @@ where }; if key == &key_new { - continue + continue; } child::put_raw(&child_trie_info, &key_new, &value); } @@ -223,7 +223,9 @@ fn default_deposit_limit() -> BalanceOf { T: Config + pallet_balances::Config, MomentOf: Into, ::RuntimeEvent: From>, + ::RuntimeCall: From>, as Currency>::Balance: From>, + ::Hash: frame_support::traits::IsType, )] mod benchmarks { use super::*; @@ -263,13 +265,12 @@ mod benchmarks { let instance = Contract::::with_caller(whitelisted_caller(), WasmModule::sized(c), vec![])?; let value = Pallet::::min_balance(); - let callee = T::AddressMapper::to_address(&instance.account_id); let storage_deposit = default_deposit_limit::(); #[extrinsic_call] call( RawOrigin::Signed(instance.caller.clone()), - callee, + instance.address, value, Weight::MAX, storage_deposit, @@ -293,9 +294,10 @@ mod benchmarks { T::Currency::set_balance(&caller, caller_funding::()); let WasmModule { code, .. } = WasmModule::sized(c); let origin = RawOrigin::Signed(caller.clone()); + Contracts::::map_account(origin.clone().into()).unwrap(); let deployer = T::AddressMapper::to_address(&caller); let addr = crate::address::create2(&deployer, &code, &input, &salt); - let account_id = T::AddressMapper::to_account_id_contract(&addr); + let account_id = T::AddressMapper::to_fallback_account_id(&addr); let storage_deposit = default_deposit_limit::(); #[extrinsic_call] _(origin, value, Weight::MAX, storage_deposit, code, input, Some(salt)); @@ -305,9 +307,14 @@ mod benchmarks { // uploading the code reserves some balance in the callers account let code_deposit = T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &caller); + let mapping_deposit = + T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &caller); assert_eq!( T::Currency::balance(&caller), - caller_funding::() - value - deposit - code_deposit - Pallet::::min_balance(), + caller_funding::() - + value - deposit - + code_deposit - mapping_deposit - + Pallet::::min_balance(), ); // contract has the full value assert_eq!(T::Currency::balance(&account_id), value + Pallet::::min_balance()); @@ -323,33 +330,31 @@ mod benchmarks { let caller = whitelisted_caller(); T::Currency::set_balance(&caller, caller_funding::()); let origin = RawOrigin::Signed(caller.clone()); + Contracts::::map_account(origin.clone().into()).unwrap(); let WasmModule { code, .. } = WasmModule::dummy(); let storage_deposit = default_deposit_limit::(); let deployer = T::AddressMapper::to_address(&caller); let addr = crate::address::create2(&deployer, &code, &input, &salt); - let hash = - Contracts::::bare_upload_code(origin.into(), code, storage_deposit)?.code_hash; - let account_id = T::AddressMapper::to_account_id_contract(&addr); + let hash = Contracts::::bare_upload_code(origin.clone().into(), code, storage_deposit)? + .code_hash; + let account_id = T::AddressMapper::to_fallback_account_id(&addr); #[extrinsic_call] - _( - RawOrigin::Signed(caller.clone()), - value, - Weight::MAX, - storage_deposit, - hash, - input, - Some(salt), - ); + _(origin, value, Weight::MAX, storage_deposit, hash, input, Some(salt)); let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id); let code_deposit = T::Currency::balance_on_hold(&HoldReason::CodeUploadDepositReserve.into(), &account_id); + let mapping_deposit = + T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &account_id); // value was removed from the caller assert_eq!( T::Currency::total_balance(&caller), - caller_funding::() - value - deposit - code_deposit - Pallet::::min_balance(), + caller_funding::() - + value - deposit - + code_deposit - mapping_deposit - + Pallet::::min_balance(), ); // contract has the full value assert_eq!(T::Currency::balance(&account_id), value + Pallet::::min_balance()); @@ -371,11 +376,10 @@ mod benchmarks { Contract::::with_caller(whitelisted_caller(), WasmModule::dummy(), vec![])?; let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); - let callee = T::AddressMapper::to_address(&instance.account_id); let before = T::Currency::balance(&instance.account_id); let storage_deposit = default_deposit_limit::(); #[extrinsic_call] - _(origin, callee, value, Weight::MAX, storage_deposit, data); + _(origin, instance.address, value, Weight::MAX, storage_deposit, data); let deposit = T::Currency::balance_on_hold( &HoldReason::StorageDepositReserve.into(), &instance.account_id, @@ -384,10 +388,15 @@ mod benchmarks { &HoldReason::CodeUploadDepositReserve.into(), &instance.caller, ); + let mapping_deposit = + T::Currency::balance_on_hold(&HoldReason::AddressMapping.into(), &instance.caller); // value and value transferred via call should be removed from the caller assert_eq!( T::Currency::balance(&instance.caller), - caller_funding::() - value - deposit - code_deposit - Pallet::::min_balance(), + caller_funding::() - + value - deposit - + code_deposit - mapping_deposit - + Pallet::::min_balance() ); // contract should have received the value assert_eq!(T::Currency::balance(&instance.account_id), before + value); @@ -447,14 +456,46 @@ mod benchmarks { let storage_deposit = default_deposit_limit::(); let hash = >::bare_upload_code(origin.into(), code, storage_deposit)?.code_hash; - let callee = T::AddressMapper::to_address(&instance.account_id); assert_ne!(instance.info()?.code_hash, hash); #[extrinsic_call] - _(RawOrigin::Root, callee, hash); + _(RawOrigin::Root, instance.address, hash); assert_eq!(instance.info()?.code_hash, hash); Ok(()) } + #[benchmark(pov_mode = Measured)] + fn map_account() { + let caller = whitelisted_caller(); + T::Currency::set_balance(&caller, caller_funding::()); + let origin = RawOrigin::Signed(caller.clone()); + assert!(!T::AddressMapper::is_mapped(&caller)); + #[extrinsic_call] + _(origin); + assert!(T::AddressMapper::is_mapped(&caller)); + } + + #[benchmark(pov_mode = Measured)] + fn unmap_account() { + let caller = whitelisted_caller(); + T::Currency::set_balance(&caller, caller_funding::()); + let origin = RawOrigin::Signed(caller.clone()); + >::map_account(origin.clone().into()).unwrap(); + assert!(T::AddressMapper::is_mapped(&caller)); + #[extrinsic_call] + _(origin); + assert!(!T::AddressMapper::is_mapped(&caller)); + } + + #[benchmark(pov_mode = Measured)] + fn dispatch_as_fallback_account() { + let caller = whitelisted_caller(); + T::Currency::set_balance(&caller, caller_funding::()); + let origin = RawOrigin::Signed(caller.clone()); + let dispatchable = frame_system::Call::remark { remark: vec![] }.into(); + #[extrinsic_call] + _(origin, Box::new(dispatchable)); + } + #[benchmark(pov_mode = Measured)] fn noop_host_fn(r: Linear<0, API_BENCHMARK_RUNS>) { let mut setup = CallSetup::::new(WasmModule::noop()); @@ -484,6 +525,24 @@ mod benchmarks { ); } + #[benchmark(pov_mode = Measured)] + fn seal_origin() { + let len = H160::len_bytes(); + build_runtime!(runtime, memory: [vec![0u8; len as _], ]); + + let result; + #[block] + { + result = runtime.bench_origin(memory.as_mut_slice(), 0); + } + + assert_ok!(result); + assert_eq!( + ::decode(&mut &memory[..]).unwrap(), + T::AddressMapper::to_address(&runtime.ext().origin().account_id().unwrap()) + ); + } + #[benchmark(pov_mode = Measured)] fn seal_is_contract() { let Contract { account_id, .. } = @@ -536,6 +595,24 @@ 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], ]); + + let result; + #[block] + { + result = runtime.bench_code_size(memory.as_mut_slice(), 0, 20); + } + + assert_ok!(result); + assert_eq!( + U256::from_little_endian(&memory[20..]), + U256::from(WasmModule::dummy().code.len()) + ); + } + #[benchmark(pov_mode = Measured)] fn seal_caller_is_origin() { build_runtime!(runtime, memory: []); @@ -636,7 +713,7 @@ mod benchmarks { build_runtime!(runtime, contract, memory: [(len as u32).encode(), vec![0u8; len],]); >::insert::<_, BoundedVec<_, _>>( - contract.address(), + contract.address, immutable_data.clone().try_into().unwrap(), ); @@ -669,10 +746,7 @@ mod benchmarks { } assert_ok!(result); - assert_eq!( - &memory[..], - &>::get(setup.contract().address()).unwrap()[..] - ); + assert_eq!(&memory[..], &>::get(setup.contract().address).unwrap()[..]); } #[benchmark(pov_mode = Measured)] @@ -711,6 +785,31 @@ mod benchmarks { assert_eq!(U256::from_little_endian(&memory[..]), runtime.ext().block_number()); } + #[benchmark(pov_mode = Measured)] + fn seal_block_hash() { + let mut memory = vec![0u8; 64]; + let mut setup = CallSetup::::default(); + let input = setup.data(); + let (mut ext, _) = setup.ext(); + ext.set_block_number(BlockNumberFor::::from(1u32)); + + let mut runtime = crate::wasm::Runtime::<_, [u8]>::new(&mut ext, input); + + let block_hash = H256::from([1; 32]); + frame_system::BlockHash::::insert( + &BlockNumberFor::::from(0u32), + T::Hash::from(block_hash), + ); + + let result; + #[block] + { + result = runtime.bench_block_hash(memory.as_mut_slice(), 32, 0); + } + assert_ok!(result); + assert_eq!(&memory[..32], &block_hash.0); + } + #[benchmark(pov_mode = Measured)] fn seal_now() { build_runtime!(runtime, memory: [[0u8;32], ]); @@ -835,7 +934,7 @@ mod benchmarks { assert_eq!( record.event, - crate::Event::ContractEmitted { contract: instance.address(), data, topics }.into(), + crate::Event::ContractEmitted { contract: instance.address, data, topics }.into(), ); } @@ -1408,36 +1507,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)] @@ -1447,7 +1516,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(); @@ -1486,25 +1555,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, ); } @@ -1522,7 +1602,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; @@ -1542,7 +1622,7 @@ mod benchmarks { let salt = [42u8; 32]; let deployer = T::AddressMapper::to_address(&account_id); let addr = crate::address::create2(&deployer, &code.code, &input, &salt); - let account_id = T::AddressMapper::to_account_id_contract(&addr); + let account_id = T::AddressMapper::to_fallback_account_id(&addr); let mut memory = memory!(hash_bytes, deposit_bytes, value_bytes, input, salt,); let mut offset = { @@ -1576,7 +1656,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/evm.rs b/substrate/frame/revive/src/evm.rs new file mode 100644 index 000000000000..c3495fc0559d --- /dev/null +++ b/substrate/frame/revive/src/evm.rs @@ -0,0 +1,22 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//!Types, and traits to integrate pallet-revive with EVM. +#![warn(missing_docs)] + +mod api; +pub use api::*; +pub mod runtime; diff --git a/substrate/frame/revive/src/evm/api.rs b/substrate/frame/revive/src/evm/api.rs new file mode 100644 index 000000000000..8185a2c8f6f8 --- /dev/null +++ b/substrate/frame/revive/src/evm/api.rs @@ -0,0 +1,40 @@ +// 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. +//! JSON-RPC methods and types, for Ethereum. + +mod byte; +pub use byte::*; + +mod rlp_codec; +pub use rlp; + +mod type_id; +pub use type_id::*; + +#[cfg(feature = "std")] +mod rpc_types; + +mod rpc_types_gen; +pub use rpc_types_gen::*; + +#[cfg(feature = "std")] +mod account; + +#[cfg(feature = "std")] +pub use account::*; + +mod signature; diff --git a/substrate/frame/revive/src/evm/api/account.rs b/substrate/frame/revive/src/evm/api/account.rs new file mode 100644 index 000000000000..8365ebf83cae --- /dev/null +++ b/substrate/frame/revive/src/evm/api/account.rs @@ -0,0 +1,60 @@ +// 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. +//! Utilities for working with Ethereum accounts. +use crate::{ + evm::{TransactionLegacySigned, TransactionLegacyUnsigned}, + H160, +}; +use rlp::Encodable; +use sp_runtime::AccountId32; + +/// 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 [`H160`] address of the account. + pub fn address(&self) -> H160 { + H160::from_slice(&self.0.public_key().to_account_id().as_ref()) + } + + /// Get the substrate [`AccountId32`] of the account. + pub fn substrate_account(&self) -> AccountId32 { + let mut account_id = AccountId32::new([0xEE; 32]); + >::as_mut(&mut account_id)[..20] + .copy_from_slice(self.address().as_ref()); + account_id + } + + /// 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()) + } +} diff --git a/substrate/frame/revive/src/evm/api/byte.rs b/substrate/frame/revive/src/evm/api/byte.rs new file mode 100644 index 000000000000..df4ed1740ecd --- /dev/null +++ b/substrate/frame/revive/src/evm/api/byte.rs @@ -0,0 +1,154 @@ +// 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. +//! Define Byte wrapper types for encoding and decoding hex strings +use alloc::{vec, vec::Vec}; +use codec::{Decode, Encode}; +use core::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + str::FromStr, +}; +use hex_serde::HexCodec; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; + +mod hex_serde { + #[cfg(not(feature = "std"))] + use alloc::{format, string::String, vec::Vec}; + use serde::{Deserialize, Deserializer, Serializer}; + + pub trait HexCodec: Sized { + type Error; + fn to_hex(&self) -> String; + fn from_hex(s: String) -> Result; + } + + impl HexCodec for u8 { + type Error = core::num::ParseIntError; + fn to_hex(&self) -> String { + format!("0x{:x}", self) + } + fn from_hex(s: String) -> Result { + u8::from_str_radix(s.trim_start_matches("0x"), 16) + } + } + + impl HexCodec for [u8; T] { + type Error = hex::FromHexError; + fn to_hex(&self) -> String { + format!("0x{}", hex::encode(self)) + } + fn from_hex(s: String) -> Result { + let data = hex::decode(s.trim_start_matches("0x"))?; + data.try_into().map_err(|_| hex::FromHexError::InvalidStringLength) + } + } + + impl HexCodec for Vec { + type Error = hex::FromHexError; + fn to_hex(&self) -> String { + format!("0x{}", hex::encode(self)) + } + fn from_hex(s: String) -> Result { + hex::decode(s.trim_start_matches("0x")) + } + } + + pub fn serialize(value: &T, serializer: S) -> Result + where + S: Serializer, + T: HexCodec, + { + let s = value.to_hex(); + serializer.serialize_str(&s) + } + + pub fn deserialize<'de, D, T>(deserializer: D) -> Result + where + D: Deserializer<'de>, + T: HexCodec, + ::Error: core::fmt::Debug, + { + let s = String::deserialize(deserializer)?; + let value = T::from_hex(s).map_err(|e| serde::de::Error::custom(format!("{:?}", e)))?; + Ok(value) + } +} + +impl FromStr for Bytes { + type Err = hex::FromHexError; + fn from_str(s: &str) -> Result { + let data = hex::decode(s.trim_start_matches("0x"))?; + Ok(Bytes(data)) + } +} + +macro_rules! impl_hex { + ($type:ident, $inner:ty, $default:expr) => { + #[derive(Encode, Decode, Eq, PartialEq, TypeInfo, Clone, Serialize, Deserialize)] + #[doc = concat!("`", stringify!($inner), "`", " wrapper type for encoding and decoding hex strings")] + pub struct $type(#[serde(with = "hex_serde")] pub $inner); + + impl Default for $type { + fn default() -> Self { + $type($default) + } + } + + impl From<$inner> for $type { + fn from(inner: $inner) -> Self { + $type(inner) + } + } + + impl Debug for $type { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, concat!(stringify!($type), "({})"), self.0.to_hex()) + } + } + + impl Display for $type { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{}", self.0.to_hex()) + } + } + }; +} + +impl_hex!(Byte, u8, 0u8); +impl_hex!(Bytes, Vec, vec![]); +impl_hex!(Bytes8, [u8; 8], [0u8; 8]); +impl_hex!(Bytes256, [u8; 256], [0u8; 256]); + +#[test] +fn serialize_works() { + let a = Byte(42); + let s = serde_json::to_string(&a).unwrap(); + assert_eq!(s, "\"0x2a\""); + let b = serde_json::from_str::(&s).unwrap(); + assert_eq!(a, b); + + let a = Bytes(b"bello world".to_vec()); + let s = serde_json::to_string(&a).unwrap(); + assert_eq!(s, "\"0x62656c6c6f20776f726c64\""); + let b = serde_json::from_str::(&s).unwrap(); + assert_eq!(a, b); + + let a = Bytes256([42u8; 256]); + let s = serde_json::to_string(&a).unwrap(); + let b = serde_json::from_str::(&s).unwrap(); + assert_eq!(a, b); +} diff --git a/substrate/frame/revive/src/evm/api/rlp_codec.rs b/substrate/frame/revive/src/evm/api/rlp_codec.rs new file mode 100644 index 000000000000..e5f24c28a482 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rlp_codec.rs @@ -0,0 +1,219 @@ +// 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. +//! RLP encoding and decoding for Ethereum transactions. +//! See for more information about RLP encoding. + +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 { + let mut s = rlp::RlpStream::new(); + s.append(self); + const DUMMY_SIGNATURE: [u8; 65] = [0u8; 65]; + s.append_raw(&DUMMY_SIGNATURE.as_ref(), 1); + s.out().to_vec() + } +} + +/// See +impl Encodable for TransactionLegacyUnsigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + if let Some(chain_id) = self.chain_id { + s.begin_list(9); + 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(&chain_id); + s.append(&0_u8); + s.append(&0_u8); + } else { + s.begin_list(6); + 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); + } + } +} + +/// See +impl Decodable for TransactionLegacyUnsigned { + fn decode(rlp: &rlp::Rlp) -> Result { + Ok(TransactionLegacyUnsigned { + nonce: rlp.val_at(0)?, + gas_price: rlp.val_at(1)?, + gas: rlp.val_at(2)?, + to: { + let to = rlp.at(3)?; + if to.is_empty() { + None + } else { + Some(to.as_val()?) + } + }, + value: rlp.val_at(4)?, + input: Bytes(rlp.val_at(5)?), + chain_id: { + if let Ok(chain_id) = rlp.val_at(6) { + Some(chain_id) + } else { + None + } + }, + ..Default::default() + }) + } +} + +impl Encodable for TransactionLegacySigned { + fn rlp_append(&self, s: &mut rlp::RlpStream) { + 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 { + 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(&self.v); + s.append(&self.r); + s.append(&self.s); + } +} + +/// See +impl Decodable for TransactionLegacySigned { + fn decode(rlp: &rlp::Rlp) -> Result { + let v: U256 = rlp.val_at(6)?; + + let extract_chain_id = |v: U256| { + if v.ge(&35u32.into()) { + Some((v - 35) / 2) + } else { + None + } + }; + + Ok(TransactionLegacySigned { + transaction_legacy_unsigned: { + TransactionLegacyUnsigned { + nonce: rlp.val_at(0)?, + gas_price: rlp.val_at(1)?, + gas: rlp.val_at(2)?, + to: { + let to = rlp.at(3)?; + if to.is_empty() { + None + } else { + Some(to.as_val()?) + } + }, + value: rlp.val_at(4)?, + input: Bytes(rlp.val_at(5)?), + chain_id: extract_chain_id(v).map(|v| v.into()), + r#type: Type0 {}, + } + }, + v, + r: rlp.val_at(7)?, + s: rlp.val_at(8)?, + }) + } +} + +#[cfg(test)] +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, + }; + + let rlp_bytes = rlp::encode(&tx); + let decoded = rlp::decode::(&rlp_bytes).unwrap(); + assert_eq!(&tx, &decoded); + + let tx = Account::default().sign_transaction(tx); + let rlp_bytes = rlp::encode(&tx); + let decoded = rlp::decode::(&rlp_bytes).unwrap(); + assert_eq!(&tx, &decoded); + } + + #[test] + fn dummy_signed_payload_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, + }; + + 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(); + + assert_eq!(account.address(), recovered_address); + } +} diff --git a/substrate/frame/revive/src/evm/api/rpc_types.rs b/substrate/frame/revive/src/evm/api/rpc_types.rs new file mode 100644 index 000000000000..dd1a2642724d --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rpc_types.rs @@ -0,0 +1,140 @@ +// 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. +//! Utility impl for the RPC types. +use super::*; +use sp_core::U256; + +impl TransactionInfo { + /// Create a new [`TransactionInfo`] from a receipt and a signed transaction. + pub fn new(receipt: ReceiptInfo, transaction_signed: TransactionSigned) -> Self { + Self { + block_hash: receipt.block_hash, + block_number: receipt.block_number, + from: receipt.from, + hash: receipt.transaction_hash, + transaction_index: receipt.transaction_index, + transaction_signed, + } + } +} + +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)); +} diff --git a/substrate/frame/revive/src/evm/api/rpc_types_gen.rs b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs new file mode 100644 index 000000000000..48045a6acc86 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/rpc_types_gen.rs @@ -0,0 +1,681 @@ +// 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. +//! Generated JSON-RPC types. +#![allow(missing_docs)] + +use super::{byte::*, Type0, Type1, Type2, Type3}; +use alloc::vec::Vec; +use codec::{Decode, Encode}; +use derive_more::{From, TryInto}; +pub use ethereum_types::*; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; + +/// Block object +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Block { + /// Base fee per gas + #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")] + pub base_fee_per_gas: Option, + /// Blob gas used + #[serde(rename = "blobGasUsed", skip_serializing_if = "Option::is_none")] + pub blob_gas_used: Option, + /// Difficulty + #[serde(skip_serializing_if = "Option::is_none")] + pub difficulty: Option, + /// Excess blob gas + #[serde(rename = "excessBlobGas", skip_serializing_if = "Option::is_none")] + pub excess_blob_gas: Option, + /// Extra data + #[serde(rename = "extraData")] + pub extra_data: Bytes, + /// Gas limit + #[serde(rename = "gasLimit")] + pub gas_limit: U256, + /// Gas used + #[serde(rename = "gasUsed")] + pub gas_used: U256, + /// Hash + pub hash: H256, + /// Bloom filter + #[serde(rename = "logsBloom")] + pub logs_bloom: Bytes256, + /// Coinbase + pub miner: Address, + /// Mix hash + #[serde(rename = "mixHash")] + pub mix_hash: H256, + /// Nonce + pub nonce: Bytes8, + /// Number + pub number: U256, + /// Parent Beacon Block Root + #[serde(rename = "parentBeaconBlockRoot", skip_serializing_if = "Option::is_none")] + pub parent_beacon_block_root: Option, + /// Parent block hash + #[serde(rename = "parentHash")] + pub parent_hash: H256, + /// Receipts root + #[serde(rename = "receiptsRoot")] + pub receipts_root: H256, + /// Ommers hash + #[serde(rename = "sha3Uncles")] + pub sha_3_uncles: H256, + /// Block size + pub size: U256, + /// State root + #[serde(rename = "stateRoot")] + pub state_root: H256, + /// Timestamp + pub timestamp: U256, + /// Total difficulty + #[serde(rename = "totalDifficulty", skip_serializing_if = "Option::is_none")] + pub total_difficulty: Option, + pub transactions: H256OrTransactionInfo, + /// Transactions root + #[serde(rename = "transactionsRoot")] + pub transactions_root: H256, + /// Uncles + pub uncles: Vec, + /// Withdrawals + #[serde(skip_serializing_if = "Option::is_none")] + pub withdrawals: Option>, + /// Withdrawals root + #[serde(rename = "withdrawalsRoot", skip_serializing_if = "Option::is_none")] + pub withdrawals_root: Option, +} + +/// Block number or tag +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum BlockNumberOrTag { + /// Block number + U256(U256), + /// Block tag + BlockTag(BlockTag), +} +impl Default for BlockNumberOrTag { + fn default() -> Self { + BlockNumberOrTag::U256(Default::default()) + } +} + +/// Block number, tag, or block hash +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum BlockNumberOrTagOrHash { + /// Block number + U256(U256), + /// Block tag + BlockTag(BlockTag), + /// Block hash + H256(H256), +} +impl Default for BlockNumberOrTagOrHash { + fn default() -> Self { + BlockNumberOrTagOrHash::U256(Default::default()) + } +} + +/// Transaction object generic to all types +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct GenericTransaction { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList", skip_serializing_if = "Option::is_none")] + 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>, + /// blobs + /// Raw blob data. + #[serde(skip_serializing_if = "Option::is_none")] + pub blobs: Option>, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] + pub chain_id: Option, + /// from address + #[serde(skip_serializing_if = "Option::is_none")] + pub from: Option
, + /// gas limit + #[serde(skip_serializing_if = "Option::is_none")] + pub gas: Option, + /// gas price + /// The gas price willing to be paid by the sender in wei + #[serde(rename = "gasPrice", skip_serializing_if = "Option::is_none")] + pub gas_price: Option, + /// input data + #[serde(alias = "data", skip_serializing_if = "Option::is_none")] + pub input: Option, + /// max fee per blob gas + /// The maximum total fee per gas the sender is willing to pay for blob gas in wei + #[serde(rename = "maxFeePerBlobGas", skip_serializing_if = "Option::is_none")] + pub max_fee_per_blob_gas: Option, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + #[serde(rename = "maxFeePerGas", skip_serializing_if = "Option::is_none")] + pub max_fee_per_gas: Option, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + #[serde(rename = "maxPriorityFeePerGas", skip_serializing_if = "Option::is_none")] + pub max_priority_fee_per_gas: Option, + /// nonce + #[serde(skip_serializing_if = "Option::is_none")] + pub nonce: Option, + /// to address + pub to: Option
, + /// type + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option, + /// value + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, +} + +/// Receipt information +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct ReceiptInfo { + /// blob gas price + /// The actual value per gas deducted from the sender's account for blob gas. Only specified + /// for blob transactions as defined by EIP-4844. + #[serde(rename = "blobGasPrice", skip_serializing_if = "Option::is_none")] + pub blob_gas_price: Option, + /// blob gas used + /// The amount of blob gas used for this specific transaction. Only specified for blob + /// transactions as defined by EIP-4844. + #[serde(rename = "blobGasUsed", skip_serializing_if = "Option::is_none")] + pub blob_gas_used: Option, + /// block hash + #[serde(rename = "blockHash")] + pub block_hash: H256, + /// block number + #[serde(rename = "blockNumber")] + pub block_number: U256, + /// contract address + /// The contract address created, if the transaction was a contract creation, otherwise null. + #[serde(rename = "contractAddress")] + pub contract_address: Option
, + /// cumulative gas used + /// The sum of gas used by this transaction and all preceding transactions in the same block. + #[serde(rename = "cumulativeGasUsed")] + pub cumulative_gas_used: U256, + /// effective gas price + /// The actual value per gas deducted from the sender's account. Before EIP-1559, this is equal + /// to the transaction's gas price. After, it is equal to baseFeePerGas + min(maxFeePerGas - + /// baseFeePerGas, maxPriorityFeePerGas). + #[serde(rename = "effectiveGasPrice")] + pub effective_gas_price: U256, + /// from + pub from: Address, + /// gas used + /// The amount of gas used for this specific transaction alone. + #[serde(rename = "gasUsed")] + pub gas_used: U256, + /// logs + pub logs: Vec, + /// logs bloom + #[serde(rename = "logsBloom")] + pub logs_bloom: Bytes256, + /// state root + /// The post-transaction state root. Only specified for transactions included before the + /// Byzantium upgrade. + #[serde(skip_serializing_if = "Option::is_none")] + pub root: Option, + /// status + /// Either 1 (success) or 0 (failure). Only specified for transactions included after the + /// Byzantium upgrade. + #[serde(skip_serializing_if = "Option::is_none")] + pub status: Option, + /// to + /// Address of the receiver or null in a contract creation transaction. + pub to: Option
, + /// transaction hash + #[serde(rename = "transactionHash")] + pub transaction_hash: H256, + /// transaction index + #[serde(rename = "transactionIndex")] + pub transaction_index: U256, + /// type + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option, +} + +/// Syncing status +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum SyncingStatus { + /// Syncing progress + SyncingProgress(SyncingProgress), + /// Not syncing + /// Should always return false if not syncing. + Bool(bool), +} +impl Default for SyncingStatus { + fn default() -> Self { + SyncingStatus::SyncingProgress(Default::default()) + } +} + +/// Transaction information +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct TransactionInfo { + /// block hash + #[serde(rename = "blockHash")] + pub block_hash: H256, + /// block number + #[serde(rename = "blockNumber")] + pub block_number: U256, + /// from address + pub from: Address, + /// transaction hash + pub hash: H256, + /// transaction index + #[serde(rename = "transactionIndex")] + pub transaction_index: U256, + #[serde(flatten)] + pub transaction_signed: TransactionSigned, +} + +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum TransactionUnsigned { + Transaction4844Unsigned(Transaction4844Unsigned), + Transaction1559Unsigned(Transaction1559Unsigned), + Transaction2930Unsigned(Transaction2930Unsigned), + TransactionLegacyUnsigned(TransactionLegacyUnsigned), +} +impl Default for TransactionUnsigned { + fn default() -> Self { + TransactionUnsigned::Transaction4844Unsigned(Default::default()) + } +} + +/// Access list +pub type AccessList = Vec; + +/// Block tag +/// `earliest`: The lowest numbered block the client has available; `finalized`: The most recent +/// crypto-economically secure block, cannot be re-orged outside of manual intervention driven by +/// community coordination; `safe`: The most recent block that is safe from re-orgs under honest +/// majority and certain synchronicity assumptions; `latest`: The most recent block in the canonical +/// chain observed by the client, this block may be re-orged out of the canonical chain even under +/// healthy/normal conditions; `pending`: A sample next block built by the client on top of `latest` +/// and containing the set of transactions usually taken from local mempool. Before the merge +/// transition is finalized, any call querying for `finalized` or `safe` block MUST be responded to +/// with `-39001: Unknown block` error +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub enum BlockTag { + #[serde(rename = "earliest")] + #[default] + Earliest, + #[serde(rename = "finalized")] + Finalized, + #[serde(rename = "safe")] + Safe, + #[serde(rename = "latest")] + Latest, + #[serde(rename = "pending")] + Pending, +} + +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum H256OrTransactionInfo { + /// Transaction hashes + H256s(Vec), + /// Full transactions + TransactionInfos(Vec), +} +impl Default for H256OrTransactionInfo { + fn default() -> Self { + H256OrTransactionInfo::H256s(Default::default()) + } +} + +/// log +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Log { + /// address + pub address: Address, + /// block hash + #[serde(rename = "blockHash", skip_serializing_if = "Option::is_none")] + pub block_hash: Option, + /// block number + #[serde(rename = "blockNumber", skip_serializing_if = "Option::is_none")] + pub block_number: Option, + /// data + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + /// log index + #[serde(rename = "logIndex", skip_serializing_if = "Option::is_none")] + pub log_index: Option, + /// removed + #[serde(skip_serializing_if = "Option::is_none")] + pub removed: Option, + /// topics + #[serde(skip_serializing_if = "Vec::is_empty")] + pub topics: Vec, + /// transaction hash + #[serde(rename = "transactionHash")] + pub transaction_hash: H256, + /// transaction index + #[serde(rename = "transactionIndex", skip_serializing_if = "Option::is_none")] + pub transaction_index: Option, +} + +/// Syncing progress +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct SyncingProgress { + /// Current block + #[serde(rename = "currentBlock", skip_serializing_if = "Option::is_none")] + pub current_block: Option, + /// Highest block + #[serde(rename = "highestBlock", skip_serializing_if = "Option::is_none")] + pub highest_block: Option, + /// Starting block + #[serde(rename = "startingBlock", skip_serializing_if = "Option::is_none")] + pub starting_block: Option, +} + +/// EIP-1559 transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction1559Unsigned { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList")] + pub access_list: AccessList, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId")] + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// gas price + /// The effective gas price paid by the sender in wei. For transactions not yet included in a + /// block, this value should be set equal to the max fee per gas. This field is DEPRECATED, + /// please transition to using effectiveGasPrice in the receipt object going forward. + #[serde(rename = "gasPrice")] + pub gas_price: U256, + /// input data + pub input: Bytes, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + #[serde(rename = "maxFeePerGas")] + pub max_fee_per_gas: U256, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + #[serde(rename = "maxPriorityFeePerGas")] + pub max_priority_fee_per_gas: U256, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: Type2, + /// value + pub value: U256, +} + +/// EIP-2930 transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction2930Unsigned { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList")] + pub access_list: AccessList, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId")] + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// gas price + /// The gas price willing to be paid by the sender in wei + #[serde(rename = "gasPrice")] + pub gas_price: U256, + /// input data + pub input: Bytes, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: Type1, + /// value + pub value: U256, +} + +/// EIP-4844 transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction4844Unsigned { + /// accessList + /// EIP-2930 access list + #[serde(rename = "accessList")] + pub access_list: AccessList, + /// blobVersionedHashes + /// List of versioned blob hashes associated with the transaction's EIP-4844 data blobs. + #[serde(rename = "blobVersionedHashes")] + pub blob_versioned_hashes: Vec, + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId")] + pub chain_id: U256, + /// gas limit + pub gas: U256, + /// input data + pub input: Bytes, + /// max fee per blob gas + /// The maximum total fee per gas the sender is willing to pay for blob gas in wei + #[serde(rename = "maxFeePerBlobGas")] + pub max_fee_per_blob_gas: U256, + /// max fee per gas + /// The maximum total fee per gas the sender is willing to pay (includes the network / base fee + /// and miner / priority fee) in wei + #[serde(rename = "maxFeePerGas")] + pub max_fee_per_gas: U256, + /// max priority fee per gas + /// Maximum fee per gas the sender is willing to pay to miners in wei + #[serde(rename = "maxPriorityFeePerGas")] + pub max_priority_fee_per_gas: U256, + /// nonce + pub nonce: U256, + /// to address + pub to: Address, + /// type + pub r#type: Type3, + /// value + pub value: U256, +} + +/// Legacy transaction. +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct TransactionLegacyUnsigned { + /// chainId + /// Chain ID that this transaction is valid on. + #[serde(rename = "chainId", skip_serializing_if = "Option::is_none")] + pub chain_id: Option, + /// gas limit + pub gas: U256, + /// gas price + /// The gas price willing to be paid by the sender in wei + #[serde(rename = "gasPrice")] + pub gas_price: U256, + /// input data + pub input: Bytes, + /// nonce + pub nonce: U256, + /// to address + pub to: Option
, + /// type + pub r#type: Type0, + /// value + pub value: U256, +} + +#[derive( + Debug, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, From, TryInto, Eq, PartialEq, +)] +#[serde(untagged)] +pub enum TransactionSigned { + Transaction4844Signed(Transaction4844Signed), + Transaction1559Signed(Transaction1559Signed), + Transaction2930Signed(Transaction2930Signed), + TransactionLegacySigned(TransactionLegacySigned), +} +impl Default for TransactionSigned { + fn default() -> Self { + TransactionSigned::Transaction4844Signed(Default::default()) + } +} + +/// Validator withdrawal +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Withdrawal { + /// recipient address for withdrawal value + pub address: Address, + /// value contained in withdrawal + pub amount: U256, + /// index of withdrawal + pub index: U256, + /// index of validator that generated withdrawal + #[serde(rename = "validatorIndex")] + pub validator_index: U256, +} + +/// Access list entry +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct AccessListEntry { + pub address: Address, + #[serde(rename = "storageKeys")] + pub storage_keys: Vec, +} + +/// Signed 1559 Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction1559Signed { + #[serde(flatten)] + pub transaction_1559_unsigned: Transaction1559Unsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + /// For backwards compatibility, `v` is optionally provided as an alternative to `yParity`. + /// This field is DEPRECATED and all use of it should migrate to `yParity`. + #[serde(skip_serializing_if = "Option::is_none")] + 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, +} + +/// Signed 2930 Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction2930Signed { + #[serde(flatten)] + pub transaction_2930_unsigned: Transaction2930Unsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + /// For backwards compatibility, `v` is optionally provided as an alternative to `yParity`. + /// This field is DEPRECATED and all use of it should migrate to `yParity`. + #[serde(skip_serializing_if = "Option::is_none")] + pub v: Option, + /// yParity + /// The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature. + #[serde(rename = "yParity")] + pub y_parity: U256, +} + +/// Signed 4844 Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct Transaction4844Signed { + #[serde(flatten)] + pub transaction_4844_unsigned: Transaction4844Unsigned, + /// r + pub r: U256, + /// s + 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, +} + +/// Signed Legacy Transaction +#[derive( + Debug, Default, Clone, Encode, Decode, TypeInfo, Serialize, Deserialize, Eq, PartialEq, +)] +pub struct TransactionLegacySigned { + #[serde(flatten)] + pub transaction_legacy_unsigned: TransactionLegacyUnsigned, + /// r + pub r: U256, + /// s + pub s: U256, + /// v + pub v: U256, +} diff --git a/substrate/frame/revive/src/evm/api/signature.rs b/substrate/frame/revive/src/evm/api/signature.rs new file mode 100644 index 000000000000..957d50c8e324 --- /dev/null +++ b/substrate/frame/revive/src/evm/api/signature.rs @@ -0,0 +1,80 @@ +// 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. +//! Ethereum signature utilities +use super::{TransactionLegacySigned, TransactionLegacyUnsigned}; +use rlp::Encodable; +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 { + if let Some(chain_id) = self.transaction_legacy_unsigned.chain_id { + // self.v - chain_id * 2 - 35 + let v: u64 = self.v.try_into().ok()?; + let chain_id: u64 = chain_id.try_into().ok()?; + let r = v.checked_sub(chain_id.checked_mul(2)?)?.checked_sub(35)?; + r.try_into().ok() + } else { + self.v.try_into().ok() + } + } + + /// Recover the Ethereum address from the 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()?) + } +} diff --git a/substrate/frame/revive/src/evm/api/type_id.rs b/substrate/frame/revive/src/evm/api/type_id.rs new file mode 100644 index 000000000000..7434ca6e9b7f --- /dev/null +++ b/substrate/frame/revive/src/evm/api/type_id.rs @@ -0,0 +1,113 @@ +// 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. +//! Ethereum Typed Transaction types +use super::Byte; +use codec::{Decode, Encode}; +use rlp::Decodable; +use scale_info::TypeInfo; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +/// A macro to generate Transaction type identifiers +/// See +macro_rules! transaction_type { + ($name:ident, $value:literal) => { + #[doc = concat!("Transaction type identifier: ", $value)] + #[derive(Clone, Default, Debug, Eq, PartialEq)] + pub struct $name; + + impl $name { + /// Get the value of the type + pub fn value(&self) -> u8 { + $value + } + + /// Convert to Byte + pub fn as_byte(&self) -> Byte { + Byte::from($value) + } + + /// Try to convert from Byte + pub fn try_from_byte(byte: Byte) -> Result { + if byte.0 == $value { + Ok(Self {}) + } else { + Err(byte) + } + } + } + + impl Decodable for $name { + fn decode(rlp: &rlp::Rlp) -> Result { + let value: u8 = rlp.as_val()?; + if value == $value { + Ok(Self {}) + } else { + Err(rlp::DecoderError::Custom(concat!("expected ", $value))) + } + } + } + + impl Encode for $name { + fn using_encoded R>(&self, f: F) -> R { + f(&[$value]) + } + } + impl Decode for $name { + fn decode(input: &mut I) -> Result { + if $value == input.read_byte()? { + Ok(Self {}) + } else { + Err(codec::Error::from(concat!("expected ", $value))) + } + } + } + + impl TypeInfo for $name { + type Identity = u8; + fn type_info() -> scale_info::Type { + ::type_info() + } + } + + impl Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(concat!("0x", $value)) + } + } + impl<'de> Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: &str = Deserialize::deserialize(deserializer)?; + if s == concat!("0x", $value) { + Ok($name {}) + } else { + Err(serde::de::Error::custom(concat!("expected ", $value))) + } + } + } + }; +} + +transaction_type!(Type0, 0); +transaction_type!(Type1, 1); +transaction_type!(Type2, 2); +transaction_type!(Type3, 3); diff --git a/substrate/frame/revive/src/evm/runtime.rs b/substrate/frame/revive/src/evm/runtime.rs new file mode 100644 index 000000000000..21294fdf6baa --- /dev/null +++ b/substrate/frame/revive/src/evm/runtime.rs @@ -0,0 +1,687 @@ +// 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. +//! Runtime types for integrating `pallet-revive` with the EVM. +use crate::{ + evm::api::{TransactionLegacySigned, TransactionLegacyUnsigned}, + AccountIdOf, AddressMapper, BalanceOf, MomentOf, Weight, LOG_TARGET, +}; +use codec::{Decode, Encode}; +use frame_support::{ + dispatch::{DispatchInfo, GetDispatchInfo}, + traits::{ExtrinsicCall, InherentBuilder, SignedTransactionBuilder}, +}; +use pallet_transaction_payment::OnChargeTransaction; +use scale_info::{StaticTypeInfo, TypeInfo}; +use sp_arithmetic::Percent; +use sp_core::{Get, H256, U256}; +use sp_runtime::{ + generic::{self, CheckedExtrinsic, ExtrinsicFormat}, + traits::{ + self, Checkable, Dispatchable, ExtrinsicLike, ExtrinsicMetadata, IdentifyAccount, Member, + TransactionExtension, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError}, + OpaqueExtrinsic, RuntimeDebug, Saturating, +}; + +use alloc::vec::Vec; + +type CallOf = ::RuntimeCall; + +/// The EVM gas price. +/// This constant is used by the proxy to advertise it via the eth_gas_price RPC. +/// +/// We use a fixed value for the gas price. +/// This let us calculate the gas estimate for a transaction with the formula: +/// `estimate_gas = substrate_fee / gas_price`. +pub const GAS_PRICE: u32 = 1u32; + +/// Wraps [`generic::UncheckedExtrinsic`] to support checking unsigned +/// [`crate::Call::eth_transact`] extrinsic. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] +pub struct UncheckedExtrinsic( + pub generic::UncheckedExtrinsic, Signature, E::Extension>, +); + +impl TypeInfo for UncheckedExtrinsic +where + Address: StaticTypeInfo, + Signature: StaticTypeInfo, + E::Extension: StaticTypeInfo, +{ + type Identity = + generic::UncheckedExtrinsic, Signature, E::Extension>; + fn type_info() -> scale_info::Type { + generic::UncheckedExtrinsic::, Signature, E::Extension>::type_info() + } +} + +impl + From, Signature, E::Extension>> + for UncheckedExtrinsic +{ + fn from( + utx: generic::UncheckedExtrinsic, Signature, E::Extension>, + ) -> Self { + Self(utx) + } +} + +impl ExtrinsicLike + for UncheckedExtrinsic +{ + fn is_bare(&self) -> bool { + ExtrinsicLike::is_bare(&self.0) + } +} + +impl ExtrinsicMetadata + for UncheckedExtrinsic +{ + const VERSION: u8 = + generic::UncheckedExtrinsic::, Signature, E::Extension>::VERSION; + type TransactionExtensions = E::Extension; +} + +impl ExtrinsicCall + for UncheckedExtrinsic +{ + type Call = CallOf; + + fn call(&self) -> &Self::Call { + self.0.call() + } +} + +use sp_runtime::traits::MaybeDisplay; +type OnChargeTransactionBalanceOf = <::OnChargeTransaction as OnChargeTransaction>::Balance; + +impl Checkable + for UncheckedExtrinsic +where + E: EthExtra, + Self: Encode, + ::Nonce: TryFrom, + ::RuntimeCall: Dispatchable, + OnChargeTransactionBalanceOf: Into>, + BalanceOf: Into + TryFrom, + MomentOf: Into, + CallOf: From> + TryInto>, + ::Hash: frame_support::traits::IsType, + + // required by Checkable for `generic::UncheckedExtrinsic` + LookupSource: Member + MaybeDisplay, + CallOf: Encode + Member + Dispatchable, + Signature: Member + traits::Verify, + ::Signer: IdentifyAccount>, + E::Extension: Encode + TransactionExtension>, + Lookup: traits::Lookup>, +{ + type Checked = CheckedExtrinsic, CallOf, E::Extension>; + + fn check(self, lookup: &Lookup) -> Result { + if !self.0.is_signed() { + if let Ok(call) = self.0.function.clone().try_into() { + if let crate::Call::eth_transact { payload, gas_limit, storage_deposit_limit } = + call + { + let checked = E::try_into_checked_extrinsic( + payload, + gas_limit, + storage_deposit_limit, + self.encoded_size(), + )?; + return Ok(checked) + }; + } + } + self.0.check(lookup) + } + + #[cfg(feature = "try-runtime")] + fn unchecked_into_checked_i_know_what_i_am_doing( + self, + lookup: &Lookup, + ) -> Result { + self.0.unchecked_into_checked_i_know_what_i_am_doing(lookup) + } +} + +impl GetDispatchInfo for UncheckedExtrinsic +where + CallOf: GetDispatchInfo + Dispatchable, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.0.get_dispatch_info() + } +} + +impl serde::Serialize + for UncheckedExtrinsic +{ + fn serialize(&self, seq: S) -> Result + where + S: ::serde::Serializer, + { + self.0.serialize(seq) + } +} + +impl<'a, Address: Decode, Signature: Decode, E: EthExtra> serde::Deserialize<'a> + for UncheckedExtrinsic +{ + fn deserialize(de: D) -> Result + where + D: serde::Deserializer<'a>, + { + let r = sp_core::bytes::deserialize(de)?; + Decode::decode(&mut &r[..]) + .map_err(|e| serde::de::Error::custom(alloc::format!("Decode error: {}", e))) + } +} + +impl SignedTransactionBuilder + for UncheckedExtrinsic +where + Address: TypeInfo, + CallOf: TypeInfo, + Signature: TypeInfo, + E::Extension: TypeInfo, +{ + type Address = Address; + type Signature = Signature; + type Extension = E::Extension; + + fn new_signed_transaction( + call: Self::Call, + signed: Address, + signature: Signature, + tx_ext: E::Extension, + ) -> Self { + generic::UncheckedExtrinsic::new_signed(call, signed, signature, tx_ext).into() + } +} + +impl InherentBuilder for UncheckedExtrinsic +where + Address: TypeInfo, + CallOf: TypeInfo, + Signature: TypeInfo, + E::Extension: TypeInfo, +{ + fn new_inherent(call: Self::Call) -> Self { + generic::UncheckedExtrinsic::new_bare(call).into() + } +} + +impl From> + for OpaqueExtrinsic +where + Address: Encode, + Signature: Encode, + CallOf: Encode, + E::Extension: Encode, +{ + fn from(extrinsic: UncheckedExtrinsic) -> Self { + Self::from_bytes(extrinsic.encode().as_slice()).expect( + "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ + raw Vec encoding; qed", + ) + } +} + +/// EthExtra convert an unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. +pub trait EthExtra { + /// The Runtime configuration. + type Config: crate::Config + pallet_transaction_payment::Config; + + /// The Runtime's transaction extension. + /// It should include at least: + /// - [`frame_system::CheckNonce`] to ensure that the nonce from the Ethereum transaction is + /// correct. + type Extension: TransactionExtension>; + + /// Get the transaction extension to apply to an unsigned [`crate::Call::eth_transact`] + /// extrinsic. + /// + /// # Parameters + /// - `nonce`: The nonce extracted from the Ethereum transaction. + /// - `tip`: The transaction tip calculated from the Ethereum transaction. + fn get_eth_extension( + nonce: ::Nonce, + tip: BalanceOf, + ) -> Self::Extension; + + /// Convert the unsigned [`crate::Call::eth_transact`] into a [`CheckedExtrinsic`]. + /// and ensure that the fees from the Ethereum transaction correspond to the fees computed from + /// the encoded_len, the injected gas_limit and storage_deposit_limit. + /// + /// # Parameters + /// - `payload`: The RLP-encoded Ethereum transaction. + /// - `gas_limit`: The gas limit for the extrinsic + /// - `storage_deposit_limit`: The storage deposit limit for the extrinsic, + /// - `encoded_len`: The encoded length of the extrinsic. + fn try_into_checked_extrinsic( + payload: Vec, + gas_limit: Weight, + storage_deposit_limit: BalanceOf, + encoded_len: usize, + ) -> Result< + CheckedExtrinsic, CallOf, Self::Extension>, + InvalidTransaction, + > + where + ::Nonce: TryFrom, + BalanceOf: Into + TryFrom, + MomentOf: Into, + ::RuntimeCall: Dispatchable, + OnChargeTransactionBalanceOf: Into>, + CallOf: From>, + ::Hash: frame_support::traits::IsType, + { + let tx = rlp::decode::(&payload).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to decode transaction: {err:?}"); + InvalidTransaction::Call + })?; + + let signer = tx.recover_eth_address().map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to recover signer: {err:?}"); + InvalidTransaction::BadProof + })?; + + let signer = + ::AddressMapper::to_fallback_account_id(&signer); + let TransactionLegacyUnsigned { nonce, chain_id, to, value, input, gas, gas_price, .. } = + tx.transaction_legacy_unsigned; + + 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 = crate::Pallet::::convert_evm_to_native(value).map_err(|err| { + log::debug!(target: LOG_TARGET, "Failed to convert value to native: {err:?}"); + InvalidTransaction::Call + })?; + + let call = if let Some(dest) = to { + crate::Call::call:: { + dest, + value, + gas_limit, + storage_deposit_limit, + data: input.0, + } + } 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))), + _ => None, + }; + + let Some((code, data)) = blob else { + log::debug!(target: LOG_TARGET, "Failed to extract polkavm code & data"); + return Err(InvalidTransaction::Call); + }; + + crate::Call::instantiate_with_code:: { + value, + gas_limit, + storage_deposit_limit, + code: code.to_vec(), + data: data.to_vec(), + salt: None, + } + }; + + let nonce = nonce.try_into().map_err(|_| InvalidTransaction::Call)?; + + // 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) + .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) + .try_into() + .map_err(|_| InvalidTransaction::Call)?; + + let info = call.get_dispatch_info(); + let function: CallOf = call.into(); + + // Fees calculated from the extrinsic, without the tip. + let actual_fee: BalanceOf = + pallet_transaction_payment::Pallet::::compute_fee( + encoded_len as u32, + &info, + Default::default(), + ) + .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()) + } + + let min = actual_fee.min(eth_fee_no_tip); + let max = actual_fee.max(eth_fee_no_tip); + let diff = Percent::from_rational(max - min, min); + if diff > Percent::from_percent(10) { + log::trace!(target: LOG_TARGET, "Difference between the extrinsic fees {actual_fee:?} and the Ethereum gas fees {eth_fee_no_tip:?} should be no more than 10% got {diff:?}"); + return Err(InvalidTransaction::Call.into()) + } else { + log::trace!(target: LOG_TARGET, "Difference between the extrinsic fees {actual_fee:?} and the Ethereum gas fees {eth_fee_no_tip:?}: {diff:?}"); + } + + let tip = eth_fee.saturating_sub(eth_fee_no_tip); + log::debug!(target: LOG_TARGET, "Created checked Ethereum transaction with nonce {nonce:?} and tip: {tip:?}"); + Ok(CheckedExtrinsic { + format: ExtrinsicFormat::Signed(signer.into(), Self::get_eth_extension(nonce, tip)), + function, + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + evm::*, + test_utils::*, + tests::{ExtBuilder, RuntimeCall, RuntimeOrigin, 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; + + #[derive(Clone, PartialEq, Eq, Debug)] + pub struct Extra; + type SignedExtra = (frame_system::CheckNonce, ChargeTransactionPayment); + + use pallet_transaction_payment::ChargeTransactionPayment; + impl EthExtra for Extra { + type Config = Test; + type Extension = SignedExtra; + + fn get_eth_extension(nonce: u32, tip: BalanceOf) -> Self::Extension { + (frame_system::CheckNonce::from(nonce), ChargeTransactionPayment::from(tip)) + } + } + + type Ex = UncheckedExtrinsic, MultiSignature, Extra>; + struct TestContext; + + impl traits::Lookup for TestContext { + type Source = MultiAddress; + type Target = AccountIdOf; + fn lookup(&self, s: Self::Source) -> Result { + match s { + MultiAddress::Id(id) => Ok(id), + _ => Err(LookupError), + } + } + } + + /// A builder for creating an unchecked extrinsic, and test that the check function works. + #[derive(Clone)] + struct UncheckedExtrinsicBuilder { + tx: TransactionLegacyUnsigned, + gas_limit: Weight, + storage_deposit_limit: BalanceOf, + } + + impl UncheckedExtrinsicBuilder { + /// Create a new builder with default values. + fn new() -> Self { + Self { + tx: TransactionLegacyUnsigned { + chain_id: Some(::ChainId::get().into()), + gas_price: U256::from(GAS_PRICE), + ..Default::default() + }, + gas_limit: Weight::zero(), + storage_deposit_limit: 0, + } + } + + fn estimate_gas(&mut self) { + let dry_run = crate::Pallet::::bare_eth_transact( + Account::default().substrate_account(), + self.tx.to, + self.tx.value.try_into().unwrap(), + self.tx.input.clone().0, + Weight::MAX, + u64::MAX, + |call| { + let call = RuntimeCall::Contracts(call); + let uxt: Ex = sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into(); + uxt.encoded_size() as u32 + }, + 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(); + 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 + } + + /// Update the transaction with the given function. + fn update(mut self, f: impl FnOnce(&mut TransactionLegacyUnsigned) -> ()) -> Self { + f(&mut self.tx); + 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.substrate_account(), + 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, + 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() + ); + }); + } + + #[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() + ); + }); + } + + #[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().substrate_account()); + + let builder = UncheckedExtrinsicBuilder::call_with(H160::from([1u8; 20])); + 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)) + ); + }); + } + + #[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)) + ); + }); + } + + #[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); + } + }); + } + + #[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); + }); + } +} diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index c6d2f205ae22..49c08166483e 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -53,7 +53,7 @@ use sp_core::{ }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Zero}, + traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, DispatchError, SaturatedConversion, }; @@ -66,6 +66,10 @@ type VarSizedKey = BoundedVec>; const FRAME_ALWAYS_EXISTS_ON_INSTANTIATE: &str = "The return value is only `None` if no contract exists at the specified address. This cannot happen on instantiate or delegate; qed"; +/// Code hash of existing account without code (keccak256 hash of empty data). +pub const EMPTY_CODE_HASH: H256 = + H256(sp_core::hex2array!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); + /// Combined key type for both fixed and variable sized storage keys. pub enum Key { /// Variant for fixed sized keys. @@ -163,6 +167,18 @@ impl Origin { Origin::Root => Err(DispatchError::RootNotAllowed), } } + + /// Make sure that this origin is mapped. + /// + /// We require an origin to be mapped in order to be used in a `Stack`. Otherwise + /// [`Stack::caller`] returns an address that can't be reverted to the original address. + fn ensure_mapped(&self) -> DispatchResult { + match self { + Self::Root => Ok(()), + Self::Signed(account_id) if T::AddressMapper::is_mapped(account_id) => Ok(()), + Self::Signed(_) => Err(>::AccountUnmapped.into()), + } + } } /// An interface that provides access to the external environment in which the @@ -194,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. /// @@ -220,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 @@ -268,13 +287,18 @@ pub trait Ext: sealing::Sealed { /// Returns the caller. fn caller(&self) -> Origin; + /// Return the origin of the whole call stack. + fn origin(&self) -> &Origin; + /// Check if a contract lives at the specified `address`. fn is_contract(&self, address: &H160) -> bool; /// Returns the code hash of the contract for the given `address`. - /// - /// Returns `None` if the `address` does not belong to a contract. - fn code_hash(&self, address: &H160) -> Option; + /// If not a contract but account exists then `keccak_256([])` is returned, otherwise `zero`. + 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; /// Returns the code hash of the contract being executed. fn own_code_hash(&mut self) -> &H256; @@ -335,6 +359,10 @@ pub trait Ext: sealing::Sealed { /// Returns the current block number. fn block_number(&self) -> U256; + /// Returns the block hash at the given `block_number` or `None` if + /// `block_number` isn't within the range of the previous 256 blocks. + fn block_hash(&self, block_number: U256) -> Option; + /// Returns the maximum allowed size of a storage item. fn max_value_size(&self) -> u32; @@ -547,8 +575,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. @@ -559,18 +587,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`. @@ -718,6 +758,7 @@ where BalanceOf: Into + TryFrom, MomentOf: Into, E: Executable, + T::Hash: frame_support::traits::IsType, { /// Create and run a new call stack by calling into `dest`. /// @@ -734,7 +775,7 @@ where dest: H160, gas_meter: &'a mut GasMeter, storage_meter: &'a mut storage::meter::Meter, - value: BalanceOf, + value: U256, input_data: Vec, debug_message: Option<&'a mut DebugBuffer>, ) -> ExecResult { @@ -749,7 +790,7 @@ where )? { stack.run(executable, input_data).map(|_| stack.first_frame.last_frame_output) } else { - Self::transfer_no_contract(&origin, &dest, value) + Self::transfer_from_origin(&origin, &origin, &dest, value) } } @@ -768,7 +809,7 @@ 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]>, debug_message: Option<&'a mut DebugBuffer>, @@ -793,7 +834,7 @@ where .map(|_| (address, stack.first_frame.last_frame_output)) } - #[cfg(all(feature = "runtime-benchmarks", feature = "riscv"))] + #[cfg(feature = "runtime-benchmarks")] pub fn bench_new_call( dest: H160, origin: Origin, @@ -811,7 +852,7 @@ where origin, gas_meter, storage_meter, - value, + value.into(), debug_message, ) .unwrap() @@ -820,16 +861,17 @@ 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, debug_message: Option<&'a mut DebugBuffer>, ) -> Result, ExecError> { + origin.ensure_mapped()?; let Some((first_frame, executable)) = Self::new_frame( args, value, @@ -838,6 +880,7 @@ where storage_meter, BalanceOf::::zero(), false, + true, )? else { return Ok(None); @@ -865,15 +908,15 @@ 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, deposit_limit: BalanceOf, 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 @@ -888,8 +931,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) }; @@ -902,7 +945,17 @@ where let address = if let Some(salt) = salt { address::create2(&deployer, executable.code(), input_data, salt) } else { - address::create1(&deployer, account_nonce.saturated_into()) + 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. + if origin_is_caller { + account_nonce.saturating_sub(1u32.into()).saturated_into() + } else { + account_nonce.saturated_into() + }, + ) }; let contract = ContractInfo::new( &address, @@ -910,7 +963,7 @@ where *executable.code_hash(), )?; ( - T::AddressMapper::to_account_id_contract(&address), + T::AddressMapper::to_fallback_account_id(&address), contract, executable, None, @@ -920,7 +973,7 @@ where }; let frame = Frame { - delegate_caller, + delegate, value_transferred, contract_info: CachedContract::Cached(contract_info), account_id, @@ -939,7 +992,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, @@ -973,6 +1026,7 @@ where nested_storage, deposit_limit, read_only, + false, )? { self.frames.try_push(frame).map_err(|_| Error::::MaxCallDepthReached)?; Ok(Some(executable)) @@ -988,7 +1042,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. @@ -1029,7 +1083,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); @@ -1061,7 +1120,13 @@ 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)?; + let account_id = T::AddressMapper::to_address(&frame.account_id); match (entry_point, delegated_code_hash) { (ExportedFunction::Constructor, _) => { @@ -1070,15 +1135,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, @@ -1092,12 +1149,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(), @@ -1225,40 +1276,61 @@ where } /// Transfer some funds from `from` to `to`. - fn transfer(from: &T::AccountId, to: &T::AccountId, value: BalanceOf) -> DispatchResult { - // this avoids events to be emitted for zero balance transfers - if !value.is_zero() { - T::Currency::transfer(from, to, value, Preservation::Preserve) - .map_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()); } - Ok(()) + + if >::account_exists(to) { + return T::Currency::transfer(from, to, value, Preservation::Preserve) + .map(|_| Default::default()) + .map_err(|_| Error::::TransferFailed.into()); + } + + 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, - ) -> DispatchResult { + 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. let from = match from { Origin::Signed(caller) => caller, - Origin::Root if value.is_zero() => return Ok(()), - Origin::Root => return DispatchError::RootNotAllowed.into(), + Origin::Root if value.is_zero() => return Ok(Default::default()), + Origin::Root => return Err(DispatchError::RootNotAllowed.into()), }; - Self::transfer(from, to, value) - } - - /// Same as `transfer_from_origin` but creates an `ExecReturnValue` on success. - fn transfer_no_contract( - from: &Origin, - to: &T::AccountId, - value: BalanceOf, - ) -> ExecResult { - Self::transfer_from_origin(from, to, value) - .map(|_| ExecReturnValue::default()) - .map_err(Into::into) + Self::transfer(origin, from, to, value) } /// Reference to the current (top) frame. @@ -1296,15 +1368,37 @@ 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 /// on the configured entry point. Thus, we allow setting the export manually. - #[cfg(all(feature = "runtime-benchmarks", feature = "riscv"))] + #[cfg(feature = "runtime-benchmarks")] pub(crate) fn override_export(&mut self, export: ExportedFunction) { self.top_frame_mut().entry_point = export; } + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) fn set_block_number(&mut self, block_number: BlockNumberFor) { + self.block_number = block_number; + } + + fn block_hash(&self, block_number: U256) -> Option { + let Ok(block_number) = BlockNumberFor::::try_from(block_number) else { + return None; + }; + if block_number >= self.block_number { + return None; + } + if block_number < self.block_number.saturating_sub(256u32.into()) { + return None; + } + Some(System::::block_hash(&block_number).into()) + } } impl<'a, T, E> Ext for Stack<'a, T, E> @@ -1313,6 +1407,7 @@ where E: Executable, BalanceOf: Into + TryFrom, MomentOf: Into, + T::Hash: frame_support::traits::IsType, { type T = T; @@ -1331,14 +1426,18 @@ where // is caught by it. self.top_frame_mut().allows_reentry = allows_reentry; - let dest = T::AddressMapper::to_account_id(dest); - let value = value.try_into().map_err(|_| Error::::BalanceConversionFailed)?; + // 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 balance transfers or when creating the frame fails. + *self.last_frame_output_mut() = Default::default(); let try_call = || { + let dest = T::AddressMapper::to_account_id(dest); if !self.allows_reentry(&dest) { return Err(>::ReentranceDenied.into()); } + let value = value.try_into().map_err(|_| Error::::BalanceConversionFailed)?; + // We ignore instantiate frames in our search for a cached contract. // Otherwise it would be possible to recursively call a contract from its own // constructor: We disallow calling not fully constructed contracts. @@ -1359,7 +1458,8 @@ where )? { self.run(executable, input_data) } else { - Self::transfer_no_contract( + Self::transfer_from_origin( + &self.origin, &Origin::from_account_id(self.account_id().clone()), &dest, value, @@ -1377,7 +1477,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(); @@ -1387,11 +1500,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) @@ -1406,6 +1523,10 @@ where input_data: Vec, salt: Option<&[u8; 32]>, ) -> Result { + // We reset the return data now, so it is cleared out even if no new frame was executed. + // This is for example the case when creating the frame fails. + *self.last_frame_output_mut() = Default::default(); + let executable = E::from_storage(code_hash, self.gas_meter_mut())?; let sender = &self.top_frame().account_id; let executable = self.push_frame( @@ -1454,14 +1575,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)?, - ) - } - fn get_storage(&mut self, key: &Key) -> Option> { self.top_frame_mut().contract_info().read(key) } @@ -1510,7 +1623,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() @@ -1520,12 +1633,30 @@ where } } + fn origin(&self) -> &Origin { + &self.origin + } + fn is_contract(&self, address: &H160) -> bool { ContractInfoOf::::contains_key(&address) } - fn code_hash(&self, address: &H160) -> Option { - >::get(&address).map(|contract| contract.code_hash) + fn code_hash(&self, address: &H160) -> H256 { + >::get(&address) + .map(|contract| contract.code_hash) + .unwrap_or_else(|| { + if System::::account_exists(&T::AddressMapper::to_account_id(address)) { + return EMPTY_CODE_HASH; + } + H256::zero() + }) + } + + fn code_size(&self, address: &H160) -> U256 { + >::get(&address) + .and_then(|contract| CodeInfoOf::::get(contract.code_hash)) + .map(|info| info.code_len()) + .unwrap_or_default() } fn own_code_hash(&mut self) -> &H256 { @@ -1546,7 +1677,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)?) } @@ -1597,6 +1734,10 @@ where self.block_number.into() } + fn block_hash(&self, block_number: U256) -> Option { + self.block_hash(block_number) + } + fn max_value_size(&self) -> u32 { limits::PAYLOAD_BYTES } @@ -1804,10 +1945,11 @@ mod tests { AddressMapper, Error, }; use assert_matches::assert_matches; - use frame_support::{assert_err, assert_ok, parameter_types}; - use frame_system::{EventRecord, Phase}; + 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; + use sp_io::hashing::keccak_256; use sp_runtime::{traits::Hash, DispatchError}; use std::{cell::RefCell, collections::hash_map::HashMap, rc::Rc}; @@ -1858,8 +2000,8 @@ mod tests { f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, ) -> H256 { Loader::mutate(|loader| { - // Generate code hashes as monotonically increasing values. - let hash = ::Hash::from_low_u64_be(loader.counter); + // Generate code hashes from contract index value. + let hash = H256(keccak_256(&loader.counter.to_le_bytes())); loader.counter += 1; loader.map.insert( hash, @@ -1957,7 +2099,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - value, + value.into(), vec![], None, ), @@ -1976,10 +2118,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)); }); } @@ -1995,7 +2182,7 @@ mod tests { ExtBuilder::default().build().execute_with(|| { place_contract(&BOB, success_ch); set_balance(&ALICE, 100); - let balance = get_balance(&BOB_CONTRACT_ID); + let balance = get_balance(&BOB_FALLBACK); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 0, value).unwrap(); @@ -2004,14 +2191,14 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], None, ) .unwrap(); assert_eq!(get_balance(&ALICE), 100 - value); - assert_eq!(get_balance(&BOB_CONTRACT_ID), balance + value); + assert_eq!(get_balance(&BOB_FALLBACK), balance + value); }); } @@ -2026,30 +2213,81 @@ 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_CONTRACT_ID); + 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![], None, - ) - .unwrap(); + )); assert_eq!(get_balance(&ALICE), 100 - value); - assert_eq!(get_balance(&BOB_CONTRACT_ID), balance + 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![], + 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![], + None, + )); }); } @@ -2074,7 +2312,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 55, + 55u64.into(), vec![], None, ) @@ -2090,16 +2328,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); }); } @@ -2122,7 +2361,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2151,7 +2390,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2180,7 +2419,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![1, 2, 3, 4], None, ); @@ -2215,7 +2454,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - min_balance, + min_balance.into(), vec![1, 2, 3, 4], Some(&[0; 32]), None, @@ -2270,7 +2509,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - value, + value.into(), vec![], None, ); @@ -2290,9 +2529,10 @@ mod tests { // Record the caller for bob. WitnessedCallerBob::mutate(|caller| { let origin = ctx.ext.caller(); - *caller = Some(::AddressMapper::to_address( - &origin.account_id().unwrap(), - )); + *caller = + Some(<::AddressMapper as AddressMapper>::to_address( + &origin.account_id().unwrap(), + )); }); // Call into CHARLIE contract. @@ -2314,7 +2554,73 @@ mod tests { // Record the caller for charlie. WitnessedCallerCharlie::mutate(|caller| { let origin = ctx.ext.caller(); - *caller = Some(::AddressMapper::to_address( + *caller = + Some(<::AddressMapper as AddressMapper>::to_address( + &origin.account_id().unwrap(), + )); + }); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, bob_ch); + place_contract(&CHARLIE, charlie_ch); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 0, 0).unwrap(); + + let result = MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + U256::zero(), + vec![], + None, + ); + + assert_matches!(result, Ok(_)); + }); + + assert_eq!(WitnessedCallerBob::get(), Some(ALICE_ADDR)); + assert_eq!(WitnessedCallerCharlie::get(), Some(BOB_ADDR)); + } + + #[test] + fn origin_returns_proper_values() { + parameter_types! { + static WitnessedCallerBob: Option = None; + static WitnessedCallerCharlie: Option = None; + } + + let bob_ch = MockLoader::insert(Call, |ctx, _| { + // Record the origin for bob. + WitnessedCallerBob::mutate(|witness| { + let origin = ctx.ext.origin(); + *witness = Some(::AddressMapper::to_address( + &origin.account_id().unwrap(), + )); + }); + + // Call into CHARLIE contract. + assert_matches!( + ctx.ext.call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false + ), + Ok(_) + ); + exec_success() + }); + let charlie_ch = MockLoader::insert(Call, |ctx, _| { + // Record the origin for charlie. + WitnessedCallerCharlie::mutate(|witness| { + let origin = ctx.ext.origin(); + *witness = Some(::AddressMapper::to_address( &origin.account_id().unwrap(), )); }); @@ -2332,7 +2638,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2341,7 +2647,7 @@ mod tests { }); assert_eq!(WitnessedCallerBob::get(), Some(ALICE_ADDR)); - assert_eq!(WitnessedCallerCharlie::get(), Some(BOB_ADDR)); + assert_eq!(WitnessedCallerCharlie::get(), Some(ALICE_ADDR)); } #[test] @@ -2364,7 +2670,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2374,16 +2680,25 @@ mod tests { #[test] fn code_hash_returns_proper_values() { - let code_bob = MockLoader::insert(Call, |ctx, _| { - // ALICE is not a contract and hence they do not have a code_hash - assert!(ctx.ext.code_hash(&ALICE_ADDR).is_none()); - // BOB is a contract and hence it has a code_hash - assert!(ctx.ext.code_hash(&BOB_ADDR).is_some()); + let bob_code_hash = MockLoader::insert(Call, |ctx, _| { + // ALICE is not a contract but account exists so it returns hash of empty data + assert_eq!(ctx.ext.code_hash(&ALICE_ADDR), EMPTY_CODE_HASH); + // BOB is a contract (this function) and hence it has a code_hash. + // `MockLoader` uses contract index to generate the code hash. + assert_eq!(ctx.ext.code_hash(&BOB_ADDR), H256(keccak_256(&0u64.to_le_bytes()))); + // [0xff;20] doesn't exist and returns hash zero + assert!(ctx.ext.code_hash(&H160([0xff; 20])).is_zero()); + exec_success() }); ExtBuilder::default().build().execute_with(|| { - place_contract(&BOB, code_bob); + // add alice account info to test case EOA code hash + frame_system::Account::::insert( + ::AddressMapper::to_account_id(&ALICE_ADDR), + AccountInfo { consumers: 1, providers: 1, ..Default::default() }, + ); + place_contract(&BOB, bob_code_hash); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 0, 0).unwrap(); // ALICE (not contract) -> BOB (contract) @@ -2392,7 +2707,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2403,7 +2718,7 @@ mod tests { #[test] fn own_code_hash_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { - let code_hash = ctx.ext.code_hash(&BOB_ADDR).unwrap(); + let code_hash = ctx.ext.code_hash(&BOB_ADDR); assert_eq!(*ctx.ext.own_code_hash(), code_hash); exec_success() }); @@ -2418,7 +2733,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2462,7 +2777,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2488,7 +2803,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2514,7 +2829,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 1, + 1u64.into(), vec![0], None, ); @@ -2558,7 +2873,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2603,7 +2918,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -2628,7 +2943,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 0, // <- zero value + U256::zero(), // <- zero value vec![], Some(&[0; 32]), None, @@ -2663,18 +2978,18 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - - min_balance, + min_balance.into(), vec![], Some(&[0 ;32]), None, ), Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address ); - let instantiated_contract_id = - ::AddressMapper::to_account_id_contract( - &instantiated_contract_address, - ); + let instantiated_contract_id = <::AddressMapper as AddressMapper< + Test, + >>::to_fallback_account_id( + &instantiated_contract_address + ); // Check that the newly created account has the expected code hash and // there are instantiation event. @@ -2718,7 +3033,7 @@ mod tests { &mut gas_meter, &mut storage_meter, - min_balance, + min_balance.into(), vec![], Some(&[0; 32]), None, @@ -2726,10 +3041,11 @@ mod tests { Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address ); - let instantiated_contract_id = - ::AddressMapper::to_account_id_contract( - &instantiated_contract_address, - ); + let instantiated_contract_id = <::AddressMapper as AddressMapper< + Test, + >>::to_fallback_account_id( + &instantiated_contract_address + ); // Check that the account has not been created. assert!(ContractInfo::::load_code_hash(&instantiated_contract_id).is_none()); @@ -2782,7 +3098,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - min_balance * 10, + (min_balance * 10).into(), vec![], None, ), @@ -2792,10 +3108,11 @@ mod tests { let instantiated_contract_address = *instantiated_contract_address.borrow().as_ref().unwrap(); - let instantiated_contract_id = - ::AddressMapper::to_account_id_contract( - &instantiated_contract_address, - ); + let instantiated_contract_id = <::AddressMapper as AddressMapper< + Test, + >>::to_fallback_account_id( + &instantiated_contract_address + ); // Check that the newly created account has the expected code hash and // there are instantiation event. @@ -2850,7 +3167,7 @@ mod tests { .build() .execute_with(|| { set_balance(&ALICE, 1000); - set_balance(&BOB_CONTRACT_ID, 100); + set_balance(&BOB_FALLBACK, 100); place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); @@ -2861,7 +3178,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ), @@ -2903,7 +3220,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 100, + 100u64.into(), vec![], Some(&[0; 32]), None, @@ -2968,7 +3285,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -2980,7 +3297,8 @@ mod tests { fn recursive_call_during_constructor_is_balance_transfer() { let code = MockLoader::insert(Constructor, |ctx, _| { let account_id = ctx.ext.account_id().clone(); - let addr = ::AddressMapper::to_address(&account_id); + let addr = + <::AddressMapper as AddressMapper>::to_address(&account_id); let balance = ctx.ext.balance(); // Calling ourselves during the constructor will trigger a balance @@ -3028,7 +3346,7 @@ mod tests { executable, &mut gas_meter, &mut storage_meter, - 10, + 10u64.into(), vec![], Some(&[0; 32]), None, @@ -3041,7 +3359,8 @@ mod tests { fn cannot_send_more_balance_than_available_to_self() { let code_hash = MockLoader::insert(Call, |ctx, _| { let account_id = ctx.ext.account_id().clone(); - let addr = ::AddressMapper::to_address(&account_id); + let addr = + <::AddressMapper as AddressMapper>::to_address(&account_id); let balance = ctx.ext.balance(); assert_err!( @@ -3074,7 +3393,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -3105,7 +3424,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], Some(&mut debug_buffer), ) @@ -3138,7 +3457,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], Some(&mut debug_buffer), ); @@ -3171,7 +3490,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], Some(&mut debug_buf_after), ) @@ -3204,7 +3523,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), CHARLIE_ADDR.as_bytes().to_vec(), None, )); @@ -3216,7 +3535,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), BOB_ADDR.as_bytes().to_vec(), None, ) @@ -3266,7 +3585,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ) @@ -3300,7 +3619,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -3313,7 +3632,7 @@ mod tests { EventRecord { phase: Phase::Initialization, event: MetaEvent::System(frame_system::Event::Remarked { - sender: BOB_CONTRACT_ID, + sender: BOB_FALLBACK, hash: remark_hash }), topics: vec![], @@ -3384,7 +3703,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -3397,7 +3716,7 @@ mod tests { EventRecord { phase: Phase::Initialization, event: MetaEvent::System(frame_system::Event::Remarked { - sender: BOB_CONTRACT_ID, + sender: BOB_FALLBACK, hash: remark_hash }), topics: vec![], @@ -3461,7 +3780,10 @@ mod tests { ) .unwrap(); - let account_id = ::AddressMapper::to_account_id_contract(&addr); + let account_id = + <::AddressMapper as AddressMapper>::to_fallback_account_id( + &addr, + ); assert_eq!(System::account_nonce(&ALICE), alice_nonce); assert_eq!(System::account_nonce(ctx.ext.account_id()), 1); @@ -3506,7 +3828,7 @@ mod tests { fail_executable, &mut gas_meter, &mut storage_meter, - min_balance * 100, + (min_balance * 100).into(), vec![], Some(&[0; 32]), None, @@ -3519,7 +3841,7 @@ mod tests { success_executable, &mut gas_meter, &mut storage_meter, - min_balance * 100, + (min_balance * 100).into(), vec![], Some(&[0; 32]), None, @@ -3531,7 +3853,7 @@ mod tests { succ_fail_executable, &mut gas_meter, &mut storage_meter, - min_balance * 200, + (min_balance * 200).into(), vec![], Some(&[0; 32]), None, @@ -3543,7 +3865,7 @@ mod tests { succ_succ_executable, &mut gas_meter, &mut storage_meter, - min_balance * 200, + (min_balance * 200).into(), vec![], Some(&[0; 32]), None, @@ -3612,7 +3934,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3723,7 +4045,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3762,7 +4084,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3801,7 +4123,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3854,7 +4176,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3910,7 +4232,7 @@ mod tests { BOB_ADDR, &mut gas_meter, &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -3985,7 +4307,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4055,7 +4377,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -4093,7 +4415,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, )); @@ -4155,7 +4477,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -4188,7 +4510,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ); @@ -4219,12 +4541,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 @@ -4254,7 +4583,7 @@ mod tests { .build() .execute_with(|| { set_balance(&ALICE, 1000); - set_balance(&BOB_CONTRACT_ID, 100); + set_balance(&BOB, 100); place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); @@ -4264,7 +4593,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4332,7 +4661,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![0], None, ); @@ -4340,6 +4669,77 @@ mod tests { }); } + #[test] + fn last_frame_output_is_always_reset() { + let code_bob = MockLoader::insert(Call, |ctx, _| { + let invalid_code_hash = H256::from_low_u64_le(u64::MAX); + let output_revert = || ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![1] }; + + // A value of u256::MAX to fail the call on the first condition. + *ctx.ext.last_frame_output_mut() = output_revert(); + assert_eq!( + ctx.ext.call( + Weight::zero(), + U256::zero(), + &H160::zero(), + U256::max_value(), + vec![], + true, + false, + ), + Err(Error::::BalanceConversionFailed.into()) + ); + assert_eq!(ctx.ext.last_frame_output(), &Default::default()); + + // 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( + Weight::zero(), + U256::zero(), + H160([0xff; 20]), + Default::default() + ), + Err(Error::::CodeNotFound.into()) + ); + assert_eq!(ctx.ext.last_frame_output(), &Default::default()); + + // An unknown code hash to fail instantiation on the first condition. + *ctx.ext.last_frame_output_mut() = output_revert(); + assert_eq!( + ctx.ext.instantiate( + Weight::zero(), + U256::zero(), + invalid_code_hash, + U256::zero(), + vec![], + None, + ), + Err(Error::::CodeNotFound.into()) + ); + assert_eq!(ctx.ext.last_frame_output(), &Default::default()); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, code_bob); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 0, 0).unwrap(); + + let result = MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + U256::zero(), + vec![], + None, + ); + assert_matches!(result, Ok(_)); + }); + } + #[test] fn immutable_data_access_checks_work() { let dummy_ch = MockLoader::insert(Constructor, move |ctx, _| { @@ -4373,7 +4773,7 @@ mod tests { .build() .execute_with(|| { set_balance(&ALICE, 1000); - set_balance(&BOB_CONTRACT_ID, 100); + set_balance(&BOB, 100); place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); @@ -4383,7 +4783,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4416,14 +4816,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() @@ -4454,7 +4852,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4490,7 +4888,7 @@ mod tests { .build() .execute_with(|| { set_balance(&ALICE, 1000); - set_balance(&BOB_CONTRACT_ID, 100); + set_balance(&BOB, 100); place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); @@ -4500,7 +4898,7 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) @@ -4534,7 +4932,7 @@ mod tests { .build() .execute_with(|| { set_balance(&ALICE, 1000); - set_balance(&BOB_CONTRACT_ID, 100); + set_balance(&BOB, 100); place_contract(&BOB, instantiator_ch); let origin = Origin::from_account_id(ALICE); let mut storage_meter = storage::meter::Meter::new(&origin, 200, 0).unwrap(); @@ -4544,11 +4942,67 @@ mod tests { BOB_ADDR, &mut GasMeter::::new(GAS_LIMIT), &mut storage_meter, - 0, + U256::zero(), vec![], None, ) .unwrap() }); } + + #[test] + fn block_hash_returns_proper_values() { + let bob_code_hash = MockLoader::insert(Call, |ctx, _| { + ctx.ext.block_number = 1u32.into(); + assert_eq!(ctx.ext.block_hash(U256::from(1)), None); + assert_eq!(ctx.ext.block_hash(U256::from(0)), Some(H256::from([1; 32]))); + + ctx.ext.block_number = 300u32.into(); + assert_eq!(ctx.ext.block_hash(U256::from(300)), None); + assert_eq!(ctx.ext.block_hash(U256::from(43)), None); + assert_eq!(ctx.ext.block_hash(U256::from(44)), Some(H256::from([2; 32]))); + + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + frame_system::BlockHash::::insert( + &BlockNumberFor::::from(0u32), + ::Hash::from([1; 32]), + ); + frame_system::BlockHash::::insert( + &BlockNumberFor::::from(1u32), + ::Hash::default(), + ); + frame_system::BlockHash::::insert( + &BlockNumberFor::::from(43u32), + ::Hash::default(), + ); + frame_system::BlockHash::::insert( + &BlockNumberFor::::from(44u32), + ::Hash::from([2; 32]), + ); + frame_system::BlockHash::::insert( + &BlockNumberFor::::from(300u32), + ::Hash::default(), + ); + + place_contract(&BOB, bob_code_hash); + + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 0, 0).unwrap(); + assert_matches!( + MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + U256::zero(), + vec![0], + None, + ), + Ok(_) + ); + }); + } } diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 6d87fd904c3f..caecf07c4071 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -23,33 +23,31 @@ extern crate alloc; mod address; mod benchmarking; -mod benchmarking_dummy; mod exec; mod gas; -mod primitives; -use crate::exec::MomentOf; -use frame_support::traits::IsType; -pub use primitives::*; -use sp_core::U256; - mod limits; +mod primitives; mod storage; mod transient_storage; mod wasm; +#[cfg(test)] +mod tests; + pub mod chain_extension; pub mod debug; +pub mod evm; pub mod test_utils; pub mod weights; -#[cfg(test)] -mod tests; use crate::{ + evm::{runtime::GAS_PRICE, TransactionLegacyUnsigned}, 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 codec::{Codec, Decode, Encode}; use environmental::*; use frame_support::{ @@ -58,9 +56,11 @@ use frame_support::{ PostDispatchInfo, RawOrigin, }, ensure, + pallet_prelude::DispatchClass, traits::{ fungible::{Inspect, Mutate, MutateHold}, - ConstU32, ConstU64, Contains, EnsureOrigin, Get, Time, + tokens::{Fortitude::Polite, Preservation::Preserve}, + ConstU32, ConstU64, Contains, EnsureOrigin, Get, IsType, OriginTrait, Time, }, weights::{Weight, WeightMeter}, BoundedVec, RuntimeDebugNoBound, @@ -70,18 +70,21 @@ use frame_system::{ pallet_prelude::{BlockNumberFor, OriginFor}, EventRecord, Pallet as System, }; +use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; -use sp_core::{H160, H256}; +use sp_core::{H160, H256, U256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Saturating}, + traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, DispatchError, }; pub use crate::{ - address::{AddressMapper, DefaultAddressMapper}, + address::{create1, create2, AccountId32Mapper, AddressMapper}, debug::Tracing, + exec::MomentOf, pallet::*, }; +pub use primitives::*; pub use weights::WeightInfo; #[cfg(doc)] @@ -90,6 +93,7 @@ pub use crate::wasm::SyscallDoc; type TrieId = BoundedVec>; type BalanceOf = <::Currency as Inspect<::AccountId>>::Balance; +type OnChargeTransactionBalanceOf = <::OnChargeTransaction as OnChargeTransaction>::Balance; type CodeVec = BoundedVec>; type EventRecordOf = EventRecord<::RuntimeEvent, ::Hash>; @@ -134,7 +138,7 @@ pub mod pallet { use sp_runtime::Perbill; /// The in-code storage version. - pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -157,10 +161,9 @@ pub mod pallet { /// The overarching call type. #[pallet::no_default_bounds] - type RuntimeCall: Dispatchable - + GetDispatchInfo - + codec::Decode - + IsType<::RuntimeCall>; + type RuntimeCall: Parameter + + Dispatchable + + GetDispatchInfo; /// Overarching hold reason. #[pallet::no_default_bounds] @@ -229,9 +232,9 @@ pub mod pallet { #[pallet::constant] type CodeHashLockupDepositPercent: Get; - /// Only valid type is [`DefaultAddressMapper`]. - #[pallet::no_default_bounds] - type AddressMapper: AddressMapper>; + /// Use either valid type is [`address::AccountId32Mapper`] or [`address::H160Mapper`]. + #[pallet::no_default] + type AddressMapper: AddressMapper; /// Make contract callable functions marked as `#[unstable]` available. /// @@ -301,6 +304,10 @@ pub mod pallet { /// preventing replay attacks. #[pallet::constant] type ChainId: Get; + + /// The ratio between the decimal representation of the native token and the ETH token. + #[pallet::constant] + type NativeToEthRatio: Get; } /// Container for different types that implement [`DefaultConfig`]` of this pallet. @@ -357,7 +364,6 @@ pub mod pallet { #[inject_runtime_type] type RuntimeCall = (); - type AddressMapper = DefaultAddressMapper; type CallFilter = (); type ChainExtension = (); type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; @@ -373,7 +379,8 @@ pub mod pallet { type Xcm = (); type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; - type ChainId = ConstU64<{ 0 }>; + type ChainId = ConstU64<0>; + type NativeToEthRatio = ConstU32<1>; } } @@ -533,6 +540,10 @@ pub mod pallet { /// The static memory consumption of the blob will be larger than /// [`limits::code::STATIC_MEMORY_BYTES`]. StaticMemoryTooLarge, + /// The program contains a basic block that is larger than allowed. + BasicBlockTooLarge, + /// The program contains an invalid instruction. + InvalidInstruction, /// The contract has reached its maximum number of delegate dependencies. MaxDelegateDependenciesReached, /// The dependency was not found in the contract's delegate dependencies. @@ -551,9 +562,17 @@ 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, + /// An `AccountID32` account tried to interact with the pallet without having a mapping. + /// + /// Call [`Pallet::map_account`] in order to create a mapping for the account. + AccountUnmapped, + /// Tried to map an account that is already mapped. + AccountAlreadyMapped, } /// A reason for the pallet contracts placing a hold on funds. @@ -563,6 +582,8 @@ pub mod pallet { CodeUploadDepositReserve, /// The Pallet has reserved it for storage deposit. StorageDepositReserve, + /// Deposit for creating an address mapping in [`AddressSuffix`]. + AddressMapping, } /// A mapping from a contract's code hash to its code. @@ -594,6 +615,14 @@ pub mod pallet { pub(crate) type DeletionQueueCounter = StorageValue<_, DeletionQueueManager, ValueQuery>; + /// Map a Ethereum address to its original `AccountId32`. + /// + /// Stores the last 12 byte for addresses that were originally an `AccountId32` instead + /// of an `H160`. Register your `AccountId32` using [`Pallet::map_account`] in order to + /// use it with this pallet. + #[pallet::storage] + pub(crate) type AddressSuffix = StorageMap<_, Identity, H160, [u8; 12]>; + #[pallet::extra_constants] impl Pallet { #[pallet::constant_name(ApiVersion)] @@ -733,7 +762,35 @@ pub mod pallet { where BalanceOf: Into + TryFrom, MomentOf: Into, + T::Hash: frame_support::traits::IsType, { + /// A raw EVM transaction, typically dispatched by an Ethereum JSON-RPC server. + /// + /// # Parameters + /// + /// * `payload`: The RLP-encoded [`crate::evm::TransactionLegacySigned`]. + /// * `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. + /// + /// # Note + /// + /// This call cannot be dispatched directly; attempting to do so will result in a failed + /// transaction. It serves as a wrapper for an Ethereum transaction. When submitted, the + /// runtime converts it into a [`sp_runtime::generic::CheckedExtrinsic`] by recovering the + /// signer and validating the transaction. + #[allow(unused_variables)] + #[pallet::call_index(0)] + #[pallet::weight(Weight::MAX)] + pub fn eth_transact( + origin: OriginFor, + payload: Vec, + gas_limit: Weight, + #[pallet::compact] storage_deposit_limit: BalanceOf, + ) -> DispatchResultWithPostInfo { + Err(frame_system::Error::CallFiltered::.into()) + } + /// Makes a call to an account, optionally transferring some balance. /// /// # Parameters @@ -750,7 +807,7 @@ pub mod pallet { /// * If the account is a regular account, any value will be transferred. /// * If no account exists and the call value is not less than `existential_deposit`, /// a regular account will be created and any value will be transferred. - #[pallet::call_index(0)] + #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::call().saturating_add(*gas_limit))] pub fn call( origin: OriginFor, @@ -760,6 +817,7 @@ pub mod pallet { #[pallet::compact] storage_deposit_limit: BalanceOf, data: Vec, ) -> DispatchResultWithPostInfo { + log::info!(target: LOG_TARGET, "Call: {:?} {:?} {:?}", dest, value, data); let mut output = Self::bare_call( origin, dest, @@ -783,7 +841,7 @@ pub mod pallet { /// This function is identical to [`Self::instantiate_with_code`] but without the /// code deployment step. Instead, the `code_hash` of an on-chain deployed wasm binary /// must be supplied. - #[pallet::call_index(1)] + #[pallet::call_index(2)] #[pallet::weight( T::WeightInfo::instantiate(data.len() as u32).saturating_add(*gas_limit) )] @@ -847,7 +905,7 @@ pub mod pallet { /// - The smart-contract account is created at the computed address. /// - The `value` is transferred to the new account. /// - The `deploy` function is executed in the context of the newly-created account. - #[pallet::call_index(2)] + #[pallet::call_index(3)] #[pallet::weight( T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32) .saturating_add(*gas_limit) @@ -898,7 +956,7 @@ pub mod pallet { /// To avoid this situation a constructor could employ access control so that it can /// only be instantiated by permissioned entities. The same is true when uploading /// through [`Self::instantiate_with_code`]. - #[pallet::call_index(3)] + #[pallet::call_index(4)] #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] pub fn upload_code( origin: OriginFor, @@ -912,7 +970,7 @@ pub mod pallet { /// /// A code can only be removed by its original uploader (its owner) and only if it is /// not used by any contract. - #[pallet::call_index(4)] + #[pallet::call_index(5)] #[pallet::weight(T::WeightInfo::remove_code())] pub fn remove_code( origin: OriginFor, @@ -934,7 +992,7 @@ pub mod pallet { /// This does **not** change the address of the contract in question. This means /// that the contract address is no longer derived from its code hash after calling /// this dispatchable. - #[pallet::call_index(5)] + #[pallet::call_index(6)] #[pallet::weight(T::WeightInfo::set_code())] pub fn set_code( origin: OriginFor, @@ -959,6 +1017,51 @@ pub mod pallet { Ok(()) }) } + + /// Register the callers account id so that it can be used in contract interactions. + /// + /// This will error if the origin is already mapped or is a eth native `Address20`. It will + /// take a deposit that can be released by calling [`Self::unmap_account`]. + #[pallet::call_index(7)] + #[pallet::weight(T::WeightInfo::map_account())] + pub fn map_account(origin: OriginFor) -> DispatchResult { + let origin = ensure_signed(origin)?; + T::AddressMapper::map(&origin) + } + + /// Unregister the callers account id in order to free the deposit. + /// + /// There is no reason to ever call this function other than freeing up the deposit. + /// This is only useful when the account should no longer be used. + #[pallet::call_index(8)] + #[pallet::weight(T::WeightInfo::unmap_account())] + pub fn unmap_account(origin: OriginFor) -> DispatchResult { + let origin = ensure_signed(origin)?; + T::AddressMapper::unmap(&origin) + } + + /// Dispatch an `call` with the origin set to the callers fallback address. + /// + /// Every `AccountId32` can control its corresponding fallback account. The fallback account + /// is the `AccountId20` with the last 12 bytes set to `0xEE`. This is essentially a + /// recovery function in case an `AccountId20` was used without creating a mapping first. + #[pallet::call_index(9)] + #[pallet::weight({ + let dispatch_info = call.get_dispatch_info(); + ( + T::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight), + dispatch_info.class + ) + })] + pub fn dispatch_as_fallback_account( + origin: OriginFor, + call: Box<::RuntimeCall>, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin)?; + let unmapped_account = + T::AddressMapper::to_fallback_account_id(&T::AddressMapper::to_address(&origin)); + call.dispatch(RawOrigin::Signed(unmapped_account).into()) + } } } @@ -982,6 +1085,7 @@ impl Pallet where BalanceOf: Into + TryFrom, MomentOf: Into, + T::Hash: frame_support::traits::IsType, { /// A generalized version of [`Self::call`]. /// @@ -998,7 +1102,7 @@ where data: Vec, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractExecResult, EventRecordOf> { + ) -> ContractResult, EventRecordOf> { let mut gas_meter = GasMeter::new(gas_limit); let mut storage_deposit = Default::default(); let mut debug_message = if matches!(debug, DebugInfo::UnsafeDebug) { @@ -1014,7 +1118,7 @@ where dest, &mut gas_meter, &mut storage_meter, - value, + Self::convert_native_to_evm(value), data, debug_message.as_mut(), )?; @@ -1027,7 +1131,7 @@ where } else { None }; - ContractExecResult { + ContractResult { result: result.map_err(|r| r.error), gas_consumed: gas_meter.gas_consumed(), gas_required: gas_meter.gas_required(), @@ -1053,7 +1157,7 @@ where salt: Option<[u8; 32]>, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractInstantiateResult, EventRecordOf> { + ) -> ContractResult, EventRecordOf> { let mut gas_meter = GasMeter::new(gas_limit); let mut storage_deposit = Default::default(); let mut debug_message = @@ -1079,7 +1183,7 @@ where executable, &mut gas_meter, &mut storage_meter, - value, + Self::convert_native_to_evm(value), data, salt.as_ref(), debug_message.as_mut(), @@ -1095,7 +1199,7 @@ where } else { None }; - ContractInstantiateResult { + ContractResult { result: output .map(|(addr, result)| InstantiateReturnValue { result, addr }) .map_err(|e| e.error), @@ -1107,6 +1211,189 @@ where } } + /// A version of [`Self::eth_transact`] used to dry-run Ethereum calls. + /// + /// # Parameters + /// + /// - `origin`: The origin of the call. + /// - `dest`: The destination address of the call. + /// - `value`: The EVM value to transfer. + /// - `input`: The input data. + /// - `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: U256, + input: Vec, + gas_limit: Weight, + storage_deposit_limit: BalanceOf, + utx_encoded_size: impl Fn(Call) -> u32, + debug: DebugInfo, + collect_events: CollectEvents, + ) -> EthContractResult> + where + T: pallet_transaction_payment::Config, + ::RuntimeCall: + Dispatchable, + ::RuntimeCall: From>, + ::RuntimeCall: Encode, + OnChargeTransactionBalanceOf: Into>, + 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); + + // Convert the value to the native balance type. + let native_value = match Self::convert_evm_to_native(value) { + Ok(v) => v, + Err(err) => + return EthContractResult { + gas_required: Default::default(), + storage_deposit: Default::default(), + fee: Default::default(), + result: Err(err.into()), + }, + }; + + // Dry run the call + let (mut result, dispatch_info) = match dest { + // 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 result = EthContractResult { + gas_required: result.gas_required, + storage_deposit: result.storage_deposit.charge_or_zero(), + result: result.result, + fee: 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 + 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), + native_value, + gas_limit, + storage_deposit_limit, + Code::Upload(code.to_vec()), + data.to_vec(), + None, + debug, + collect_events, + ); + + let result = EthContractResult { + gas_required: result.gas_required, + storage_deposit: result.storage_deposit.charge_or_zero(), + result: result.result.map(|v| v.result), + fee: 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()) + }, + }; + + let mut tx = TransactionLegacyUnsigned { + value, + input: input.into(), + nonce: nonce.into(), + chain_id: Some(T::ChainId::get().into()), + gas_price: GAS_PRICE.into(), + to: dest, + ..Default::default() + }; + + // 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 eth_dispatch_call = crate::Call::::eth_transact { + payload: tx.dummy_signed_payload(), + gas_limit: result.gas_required, + storage_deposit_limit: result.storage_deposit, + }; + let encoded_len = utx_encoded_size(eth_dispatch_call); + let fee = pallet_transaction_payment::Pallet::::compute_fee( + encoded_len, + &dispatch_info, + 0u32.into(), + ) + .into(); + + if fee == result.fee { + log::trace!(target: LOG_TARGET, "bare_eth_call: encoded_len: {encoded_len:?} fee: {fee:?}"); + break; + } + result.fee = fee; + tx.gas = (fee / GAS_PRICE.into()).into(); + log::debug!(target: LOG_TARGET, "Adjusting Eth gas to: {:?}", tx.gas); + } + + 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`]. /// /// It is identical to [`Self::upload_code`] and only differs in the information it returns. @@ -1159,6 +1446,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 { @@ -1179,12 +1485,19 @@ environmental!(executing_contract: bool); sp_api::decl_runtime_apis! { /// The API used to dry-run contract interactions. #[api_version(1)] - pub trait ReviveApi where + pub trait ReviveApi where AccountId: Codec, Balance: Codec, + Nonce: Codec, BlockNumber: Codec, EventRecord: Codec, { + /// 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; + /// Perform a call from a specified account to a given contract. /// /// See [`crate::Pallet::bare_call`]. @@ -1195,7 +1508,7 @@ sp_api::decl_runtime_apis! { gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, - ) -> ContractExecResult; + ) -> ContractResult; /// Instantiate a new contract. /// @@ -1208,7 +1521,20 @@ sp_api::decl_runtime_apis! { code: Code, data: Vec, salt: Option<[u8; 32]>, - ) -> ContractInstantiateResult; + ) -> ContractResult; + + + /// Perform an Ethereum call. + /// + /// See [`crate::Pallet::bare_eth_transact`] + fn eth_transact( + origin: H160, + dest: Option, + value: U256, + input: Vec, + gas_limit: Option, + storage_deposit_limit: Option, + ) -> EthContractResult; /// 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 50cdba6d0c91..64e66382b9ab 100644 --- a/substrate/frame/revive/src/limits.rs +++ b/substrate/frame/revive/src/limits.rs @@ -36,7 +36,7 @@ /// /// A 0 means that no callings of other contracts are possible. In other words only the origin /// called "root contract" is allowed to execute then. -pub const CALL_STACK_DEPTH: u32 = 10; +pub const CALL_STACK_DEPTH: u32 = 5; /// The maximum number of topics a call to [`crate::SyscallDoc::deposit_event`] can emit. /// @@ -82,7 +82,6 @@ pub mod code { use super::PAGE_SIZE; use crate::{CodeVec, Config, Error, LOG_TARGET}; use alloc::vec::Vec; - use frame_support::ensure; use sp_runtime::DispatchError; /// The maximum length of a code blob in bytes. @@ -98,7 +97,7 @@ pub mod code { /// for more code or more data. However, since code will decompress /// into a bigger representation on compilation it will only increase /// the allowed code size by [`BYTE_PER_INSTRUCTION`]. - pub const STATIC_MEMORY_BYTES: u32 = 1024 * 1024; + pub const STATIC_MEMORY_BYTES: u32 = 2 * 1024 * 1024; /// How much memory each instruction will take in-memory after compilation. /// @@ -109,6 +108,13 @@ pub mod code { /// The code is stored multiple times as part of the compiled program. const EXTRA_OVERHEAD_PER_CODE_BYTE: u32 = 4; + /// The maximum size of a basic block in number of instructions. + /// + /// We need to limit the size of basic blocks because the interpreters lazy compilation + /// compiles one basic block at a time. A malicious program could trigger the compilation + /// of the whole program by creating one giant basic block otherwise. + const BASIC_BLOCK_SIZE: u32 = 1000; + /// Make sure that the various program parts are within the defined limits. pub fn enforce(blob: Vec) -> Result { fn round_page(n: u32) -> u64 { @@ -123,8 +129,30 @@ pub mod code { Error::::CodeRejected })?; - // this is O(n) but it allows us to be more precise - let num_instructions = program.instructions().count() as u64; + // 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; + 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) { + 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()) + } + } + + if max_basic_block_size > BASIC_BLOCK_SIZE { + log::debug!(target: LOG_TARGET, "basic block too large: {max_basic_block_size} limit: {BASIC_BLOCK_SIZE}"); + return Err(Error::::BasicBlockTooLarge.into()) + } // The memory consumptions is the byte size of the whole blob, // minus the RO data payload in the blob, @@ -139,12 +167,17 @@ pub mod code { .saturating_add(round_page(program.rw_data_size())) .saturating_sub(program.rw_data().len() as u64) .saturating_add(round_page(program.stack_size())) - .saturating_add((num_instructions).saturating_mul(BYTES_PER_INSTRUCTION.into())) + .saturating_add( + u64::from(num_instructions).saturating_mul(BYTES_PER_INSTRUCTION.into()), + ) .saturating_add( (program.code().len() as u64).saturating_mul(EXTRA_OVERHEAD_PER_CODE_BYTE.into()), ); - ensure!(memory_size <= STATIC_MEMORY_BYTES as u64, >::StaticMemoryTooLarge); + if memory_size > STATIC_MEMORY_BYTES.into() { + log::debug!(target: LOG_TARGET, "static memory too large: {memory_size} limit: {STATIC_MEMORY_BYTES}"); + return Err(Error::::StaticMemoryTooLarge.into()) + } Ok(blob) } diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index 67bc144c3dd2..024b1f3448e1 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -76,19 +76,24 @@ pub struct ContractResult { /// RPC calls. pub debug_message: Vec, /// The execution result of the wasm code. - pub result: R, + pub result: Result, /// The events that were emitted during execution. It is an option as event collection is /// optional. pub events: Option>, } -/// Result type of a `bare_call` call as well as `ContractsApi::call`. -pub type ContractExecResult = - ContractResult, Balance, EventRecord>; - -/// Result type of a `bare_instantiate` call as well as `ContractsApi::instantiate`. -pub type ContractInstantiateResult = - ContractResult, Balance, EventRecord>; +/// 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, + /// 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: R, +} /// Result type of a `bare_code_upload` call. pub type CodeUploadResult = Result, DispatchError>; diff --git a/substrate/frame/revive/src/storage.rs b/substrate/frame/revive/src/storage.rs index db4db3e8eac3..b7156588d44c 100644 --- a/substrate/frame/revive/src/storage.rs +++ b/substrate/frame/revive/src/storage.rs @@ -505,7 +505,6 @@ impl DeletionQueueManager { } #[cfg(test)] -#[cfg(feature = "riscv")] impl DeletionQueueManager { pub fn from_test_values(insert_counter: u32, delete_counter: u32) -> Self { Self { insert_counter, delete_counter, _phantom: Default::default() } diff --git a/substrate/frame/revive/src/test_utils.rs b/substrate/frame/revive/src/test_utils.rs index 92c21297a3ec..acd9a4cda38a 100644 --- a/substrate/frame/revive/src/test_utils.rs +++ b/substrate/frame/revive/src/test_utils.rs @@ -27,38 +27,35 @@ use frame_support::weights::Weight; use sp_core::H160; pub use sp_runtime::AccountId32; -const fn ee_suffix(addr: H160) -> AccountId32 { - let mut id = [0u8; 32]; - let mut i = 0; - while i < 20 { - id[i] = addr.0[i]; +const fn ee_suffix(mut account: [u8; 32]) -> AccountId32 { + let mut i = 20; + while i < 32 { + account[i] = 0xee; i += 1; } - - let mut j = 20; - while j < 32 { - id[j] = 0xee; - j += 1; - } - - AccountId32::new(id) + AccountId32::new(account) } -pub const ALICE: AccountId32 = AccountId32::new([1u8; 32]); +pub const ALICE: AccountId32 = ee_suffix([1u8; 32]); pub const ALICE_ADDR: H160 = H160([1u8; 20]); -pub const ETH_ALICE: AccountId32 = ee_suffix(ALICE_ADDR); +pub const ALICE_FALLBACK: AccountId32 = ee_suffix([1u8; 32]); -pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); +pub const BOB: AccountId32 = ee_suffix([2u8; 32]); pub const BOB_ADDR: H160 = H160([2u8; 20]); -pub const BOB_CONTRACT_ID: AccountId32 = ee_suffix(BOB_ADDR); +pub const BOB_FALLBACK: AccountId32 = ee_suffix([2u8; 32]); -pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); +pub const CHARLIE: AccountId32 = ee_suffix([3u8; 32]); pub const CHARLIE_ADDR: H160 = H160([3u8; 20]); -pub const CHARLIE_CONTRACT_ID: AccountId32 = ee_suffix(CHARLIE_ADDR); +pub const CHARLIE_FALLBACK: AccountId32 = ee_suffix([3u8; 32]); -pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); +pub const DJANGO: AccountId32 = ee_suffix([4u8; 32]); pub const DJANGO_ADDR: H160 = H160([4u8; 20]); -pub const ETH_DJANGO: AccountId32 = ee_suffix(DJANGO_ADDR); +pub const DJANGO_FALLBACK: AccountId32 = ee_suffix([4u8; 32]); + +/// Eve is a non ee account and hence needs a stateful mapping. +pub const EVE: AccountId32 = AccountId32::new([5u8; 32]); +pub const EVE_ADDR: H160 = H160([5u8; 20]); +pub const EVE_FALLBACK: AccountId32 = ee_suffix([5u8; 32]); pub const GAS_LIMIT: Weight = Weight::from_parts(100_000_000_000, 3 * 1024 * 1024); diff --git a/substrate/frame/revive/src/test_utils/builder.rs b/substrate/frame/revive/src/test_utils/builder.rs index d361590df95a..e64f58894432 100644 --- a/substrate/frame/revive/src/test_utils/builder.rs +++ b/substrate/frame/revive/src/test_utils/builder.rs @@ -17,9 +17,8 @@ use super::{deposit_limit, GAS_LIMIT}; use crate::{ - address::AddressMapper, AccountIdOf, BalanceOf, Code, CollectEvents, Config, - ContractExecResult, ContractInstantiateResult, DebugInfo, EventRecordOf, ExecReturnValue, - InstantiateReturnValue, OriginFor, Pallet, Weight, + address::AddressMapper, AccountIdOf, BalanceOf, Code, CollectEvents, Config, ContractResult, + DebugInfo, EventRecordOf, ExecReturnValue, InstantiateReturnValue, OriginFor, Pallet, Weight, }; use frame_support::pallet_prelude::DispatchResultWithPostInfo; use paste::paste; @@ -140,7 +139,7 @@ builder!( salt: Option<[u8; 32]>, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractInstantiateResult, EventRecordOf>; + ) -> ContractResult, EventRecordOf>; /// Build the instantiate call and unwrap the result. pub fn build_and_unwrap_result(self) -> InstantiateReturnValue { @@ -203,7 +202,7 @@ builder!( data: Vec, debug: DebugInfo, collect_events: CollectEvents, - ) -> ContractExecResult, EventRecordOf>; + ) -> ContractResult, EventRecordOf>; /// Build the call and unwrap the result. pub fn build_and_unwrap_result(self) -> ExecReturnValue { diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index c7d1a8b2cf0d..177b8dff706b 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -15,8 +15,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![cfg_attr(not(feature = "riscv"), allow(dead_code, unused_imports, unused_macros))] - mod pallet_dummy; mod test_debug; @@ -39,9 +37,9 @@ use crate::{ tests::test_utils::{get_contract, get_contract_checked}, wasm::Memory, weights::WeightInfo, - BalanceOf, Code, CodeInfoOf, CollectEvents, Config, ContractInfo, ContractInfoOf, DebugInfo, - DefaultAddressMapper, DeletionQueueCounter, Error, HoldReason, Origin, Pallet, PristineCode, - H160, + AccountId32Mapper, BalanceOf, Code, CodeInfoOf, CollectEvents, Config, ContractInfo, + ContractInfoOf, DebugInfo, DeletionQueueCounter, Error, HoldReason, Origin, Pallet, + PristineCode, H160, }; use crate::test_utils::builder::Contract; @@ -58,16 +56,19 @@ use frame_support::{ tokens::Preservation, ConstU32, ConstU64, Contains, OnIdle, OnInitialize, StorageVersion, }, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightMeter}, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, FixedFee, IdentityFee, Weight, WeightMeter}, }; use frame_system::{EventRecord, Phase}; use pallet_revive_fixtures::{bench::dummy_unique, compile_module}; use pallet_revive_uapi::ReturnErrorCode as RuntimeReturnCode; +use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier}; +use pretty_assertions::{assert_eq, assert_ne}; +use sp_core::U256; use sp_io::hashing::blake2_256; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::{ testing::H256, - traits::{BlakeTwo256, Convert, IdentityLookup}, + traits::{BlakeTwo256, Convert, IdentityLookup, One}, AccountId32, BuildStorage, DispatchError, Perbill, TokenError, }; @@ -82,6 +83,7 @@ frame_support::construct_runtime!( Utility: pallet_utility, Contracts: pallet_revive, Proxy: pallet_proxy, + TransactionPayment: pallet_transaction_payment, Dummy: pallet_dummy } ); @@ -112,7 +114,8 @@ pub mod test_utils { pub fn place_contract(address: &AccountIdOf, code_hash: sp_core::H256) { set_balance(address, Contracts::min_balance() * 10); >::insert(code_hash, CodeInfo::new(address.clone())); - let address = ::AddressMapper::to_address(&address); + let address = + <::AddressMapper as AddressMapper>::to_address(&address); let contract = >::new(&address, 0, code_hash).unwrap(); >::insert(address, contract); } @@ -415,6 +418,18 @@ impl pallet_proxy::Config for Test { type AnnouncementDepositFactor = ConstU64<1>; } +parameter_types! { + pub FeeMultiplier: Multiplier = Multiplier::one(); +} + +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] +impl pallet_transaction_payment::Config for Test { + type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; + type WeightToFee = IdentityFee<::Balance>; + type LengthToFee = FixedFee<100, ::Balance>; + type FeeMultiplierUpdate = ConstFeeMultiplier; +} + impl pallet_dummy::Config for Test {} parameter_types! { @@ -494,13 +509,13 @@ parameter_types! { #[derive_impl(crate::config_preludes::TestDefaultConfig)] impl Config for Test { type Time = Timestamp; + type AddressMapper = AccountId32Mapper; type Currency = Balances; type CallFilter = TestFilter; type ChainExtension = (TestExtension, DisabledExtension, RevertingExtension, TempStorageExtension); type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; - type AddressMapper = DefaultAddressMapper; type UnsafeUnstableInterface = UnstableInterface; type UploadOrigin = EnsureAccount; type InstantiateOrigin = EnsureAccount; @@ -509,6 +524,17 @@ impl Config for Test { type ChainId = ChainId; } +impl TryFrom for crate::Call { + type Error = (); + + fn try_from(value: RuntimeCall) -> Result { + match value { + RuntimeCall::Contracts(call) => Ok(call), + _ => Err(()), + } + } +} + pub struct ExtBuilder { existential_deposit: u64, storage_version: Option, @@ -598,1299 +624,1470 @@ impl Default for Origin { } } -/// We can only run the tests if we have a riscv toolchain installed -#[cfg(feature = "riscv")] -mod run_tests { - use super::*; - use pretty_assertions::{assert_eq, assert_ne}; - use sp_core::U256; +#[test] +fn calling_plain_account_is_balance_transfer() { + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 100_000_000); + 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 + ::Currency::minimum_balance() + ); + assert_eq!(result, Default::default()); + }); +} - #[test] - fn calling_plain_account_is_balance_transfer() { - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 100_000_000); - assert!(!>::contains_key(BOB_ADDR)); - assert_eq!(test_utils::get_balance(&BOB_CONTRACT_ID), 0); - let result = builder::bare_call(BOB_ADDR).value(42).build_and_unwrap_result(); - assert_eq!(test_utils::get_balance(&BOB_CONTRACT_ID), 42); - assert_eq!(result, Default::default()); - }); - } +#[test] +fn instantiate_and_call_and_deposit_event() { + let (wasm, code_hash) = compile_module("event_and_return_on_deploy").unwrap(); - #[test] - fn instantiate_and_call_and_deposit_event() { - let (wasm, code_hash) = compile_module("event_and_return_on_deploy").unwrap(); + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let value = 100; - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let value = 100; + // We determine the storage deposit limit after uploading because it depends on ALICEs + // free balance which is changed by uploading a module. + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm, + deposit_limit::(), + )); + + // Drop previous events + initialize_block(2); + + // Check at the end to get hash on error easily + let Contract { addr, account_id } = builder::bare_instantiate(Code::Existing(code_hash)) + .value(value) + .build_and_unwrap_contract(); + assert!(ContractInfoOf::::contains_key(&addr)); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: account_id.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: account_id.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: value, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::ContractEmitted { + contract: addr, + data: vec![1, 2, 3, 4], + topics: vec![H256::repeat_byte(42)], + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: ALICE_ADDR, + contract: addr + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndHeld { + from: ALICE_ADDR, + to: addr, + amount: test_utils::contract_info_storage_deposit(&addr), + } + ), + topics: vec![], + }, + ] + ); + }); +} - // We determine the storage deposit limit after uploading because it depends on ALICEs - // free balance which is changed by uploading a module. - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm, - deposit_limit::(), - )); +#[test] +fn create1_address_from_extrinsic() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); - // Drop previous events - initialize_block(2); + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Check at the end to get hash on error easily - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Existing(code_hash)) - .value(value) - .build_and_unwrap_contract(); - assert!(ContractInfoOf::::contains_key(&addr)); + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + deposit_limit::(), + )); + assert_eq!(System::account_nonce(&ALICE), 0); + System::inc_account_nonce(&ALICE); + + for nonce in 1..3 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .salt(None) + .build_and_unwrap_contract(); + assert!(ContractInfoOf::::contains_key(&addr)); assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: account_id.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: account_id.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: value, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::ContractEmitted { - contract: addr, - data: vec![1, 2, 3, 4], - topics: vec![H256::repeat_byte(42)], - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: ALICE_ADDR, - contract: addr - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndHeld { - from: ALICE_ADDR, - to: addr, - amount: test_utils::contract_info_storage_deposit(&addr), - } - ), - topics: vec![], - }, - ] + addr, + create1(&::AddressMapper::to_address(&ALICE), nonce - 1) ); - }); - } - - #[test] - fn create1_address_from_extrinsic() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm.clone(), - deposit_limit::(), - )); + } + assert_eq!(System::account_nonce(&ALICE), 3); - assert_eq!(System::account_nonce(&ALICE), 0); + for nonce in 3..6 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) + .salt(None) + .build_and_unwrap_contract(); + assert!(ContractInfoOf::::contains_key(&addr)); + assert_eq!( + addr, + create1(&::AddressMapper::to_address(&ALICE), nonce - 1) + ); + } + assert_eq!(System::account_nonce(&ALICE), 6); + }); +} - for nonce in 0..3 { - let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) - .salt(None) - .build_and_unwrap_contract(); - assert!(ContractInfoOf::::contains_key(&addr)); - assert_eq!( - addr, - create1(&::AddressMapper::to_address(&ALICE), nonce) - ); - } - assert_eq!(System::account_nonce(&ALICE), 3); +#[test] +fn deposit_event_max_value_limit() { + let (wasm, _code_hash) = compile_module("event_size").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_contract(); + + // Call contract with allowed storage value. + assert_ok!(builder::call(addr) + .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer, + .data(limits::PAYLOAD_BYTES.encode()) + .build()); + + // Call contract with too large a storage value. + assert_err_ignore_postinfo!( + builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), + Error::::ValueTooLarge, + ); + }); +} - for nonce in 3..6 { - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) - .salt(None) - .build_and_unwrap_contract(); - assert!(ContractInfoOf::::contains_key(&addr)); - assert_eq!( - addr, - create1(&::AddressMapper::to_address(&ALICE), nonce) - ); - } - assert_eq!(System::account_nonce(&ALICE), 6); - }); - } +// Fail out of fuel (ref_time weight) in the engine. +#[test] +fn run_out_of_fuel_engine() { + let (wasm, _code_hash) = compile_module("run_out_of_gas").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(100 * min_balance) + .build_and_unwrap_contract(); + + // Call the contract with a fixed gas limit. It must run out of gas because it just + // loops forever. + assert_err_ignore_postinfo!( + builder::call(addr) + .gas_limit(Weight::from_parts(10_000_000_000, u64::MAX)) + .build(), + Error::::OutOfGas, + ); + }); +} - #[test] - fn deposit_event_max_value_limit() { - let (wasm, _code_hash) = compile_module("event_size").unwrap(); +// Fail out of fuel (ref_time weight) in the host. +#[test] +fn run_out_of_fuel_host() { + let (code, _hash) = compile_module("chain_extension").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + let gas_limit = Weight::from_parts(u32::MAX as u64, GAS_LIMIT.proof_size()); + + // Use chain extension to charge more ref_time than it is available. + let result = builder::bare_call(addr) + .gas_limit(gas_limit) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &u32::MAX.encode() }.into()) + .build() + .result; + assert_err!(result, >::OutOfGas); + }); +} - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(30_000) - .build_and_unwrap_contract(); +#[test] +fn gas_syncs_work() { + let (code, _code_hash) = compile_module("caller_is_origin_n").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let contract = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let result = builder::bare_call(contract.addr).data(0u32.encode()).build(); + assert_ok!(result.result); + let engine_consumed_noop = result.gas_consumed.ref_time(); + + let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); + assert_ok!(result.result); + let gas_consumed_once = result.gas_consumed.ref_time(); + let host_consumed_once = ::WeightInfo::seal_caller_is_origin().ref_time(); + let engine_consumed_once = gas_consumed_once - host_consumed_once - engine_consumed_noop; + + let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); + assert_ok!(result.result); + let gas_consumed_twice = result.gas_consumed.ref_time(); + let host_consumed_twice = host_consumed_once * 2; + let engine_consumed_twice = gas_consumed_twice - host_consumed_twice - engine_consumed_noop; + + // Second contract just repeats first contract's instructions twice. + // If runtime syncs gas with the engine properly, this should pass. + assert_eq!(engine_consumed_twice, engine_consumed_once * 2); + }); +} - // Call contract with allowed storage value. - assert_ok!(builder::call(addr) - .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer, - .data(limits::PAYLOAD_BYTES.encode()) - .build()); +/// Check that contracts with the same account id have different trie ids. +/// Check the `Nonce` storage item for more information. +#[test] +fn instantiate_unique_trie_id() { + let (wasm, code_hash) = compile_module("self_destruct").unwrap(); - // Call contract with too large a storage value. - assert_err_ignore_postinfo!( - builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), - Error::::ValueTooLarge, - ); - }); - } + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, deposit_limit::()) + .unwrap(); - // Fail out of fuel (ref_time weight) in the engine. - #[test] - fn run_out_of_fuel_engine() { - let (wasm, _code_hash) = compile_module("run_out_of_gas").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Instantiate the contract and store its trie id for later comparison. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Existing(code_hash)).build_and_unwrap_contract(); + let trie_id = get_contract(&addr).trie_id; - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(100 * min_balance) - .build_and_unwrap_contract(); + // Try to instantiate it again without termination should yield an error. + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).build(), + >::DuplicateContract, + ); - // Call the contract with a fixed gas limit. It must run out of gas because it just - // loops forever. - assert_err_ignore_postinfo!( - builder::call(addr) - .gas_limit(Weight::from_parts(10_000_000_000, u64::MAX)) - .build(), - Error::::OutOfGas, - ); - }); - } + // Terminate the contract. + assert_ok!(builder::call(addr).build()); - // Fail out of fuel (ref_time weight) in the host. - #[test] - fn run_out_of_fuel_host() { - let (code, _hash) = compile_module("chain_extension").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + // Re-Instantiate after termination. + assert_ok!(builder::instantiate(code_hash).build()); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + // Trie ids shouldn't match or we might have a collision + assert_ne!(trie_id, get_contract(&addr).trie_id); + }); +} - let gas_limit = Weight::from_parts(u32::MAX as u64, GAS_LIMIT.proof_size()); +#[test] +fn storage_work() { + let (code, _code_hash) = compile_module("storage").unwrap(); - // Use chain extension to charge more ref_time than it is available. - let result = builder::bare_call(addr) - .gas_limit(gas_limit) - .data( - ExtensionInput { extension_id: 0, func_id: 2, extra: &u32::MAX.encode() } - .into(), - ) - .build() - .result; - assert_err!(result, >::OutOfGas); - }); - } + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - #[test] - fn gas_syncs_work() { - let (code, _code_hash) = compile_module("caller_is_origin_n").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let contract = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - - let result = builder::bare_call(contract.addr).data(0u32.encode()).build(); - assert_ok!(result.result); - let engine_consumed_noop = result.gas_consumed.ref_time(); - - let result = builder::bare_call(contract.addr).data(1u32.encode()).build(); - assert_ok!(result.result); - let gas_consumed_once = result.gas_consumed.ref_time(); - let host_consumed_once = - ::WeightInfo::seal_caller_is_origin().ref_time(); - let engine_consumed_once = - gas_consumed_once - host_consumed_once - engine_consumed_noop; - - let result = builder::bare_call(contract.addr).data(2u32.encode()).build(); - assert_ok!(result.result); - let gas_consumed_twice = result.gas_consumed.ref_time(); - let host_consumed_twice = host_consumed_once * 2; - let engine_consumed_twice = - gas_consumed_twice - host_consumed_twice - engine_consumed_noop; - - // Second contract just repeats first contract's instructions twice. - // If runtime syncs gas with the engine properly, this should pass. - assert_eq!(engine_consumed_twice, engine_consumed_once * 2); - }); - } + builder::bare_call(addr).build_and_unwrap_result(); + }); +} - /// Check that contracts with the same account id have different trie ids. - /// Check the `Nonce` storage item for more information. - #[test] - fn instantiate_unique_trie_id() { - let (wasm, code_hash) = compile_module("self_destruct").unwrap(); +#[test] +fn storage_max_value_limit() { + let (wasm, _code_hash) = compile_module("storage_size").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_contract(); + get_contract(&addr); + + // Call contract with allowed storage value. + assert_ok!(builder::call(addr) + .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer + .data(limits::PAYLOAD_BYTES.encode()) + .build()); + + // Call contract with too large a storage value. + assert_err_ignore_postinfo!( + builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), + Error::::ValueTooLarge, + ); + }); +} - ExtBuilder::default().existential_deposit(500).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, deposit_limit::()) - .unwrap(); +#[test] +fn transient_storage_work() { + let (code, _code_hash) = compile_module("transient_storage").unwrap(); - // Instantiate the contract and store its trie id for later comparison. - let Contract { addr, .. } = - builder::bare_instantiate(Code::Existing(code_hash)).build_and_unwrap_contract(); - let trie_id = get_contract(&addr).trie_id; + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // Try to instantiate it again without termination should yield an error. - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).build(), - >::DuplicateContract, - ); + builder::bare_call(addr).build_and_unwrap_result(); + }); +} - // Terminate the contract. - assert_ok!(builder::call(addr).build()); +#[test] +fn transient_storage_limit_in_call() { + let (wasm_caller, _code_hash_caller) = + compile_module("create_transient_storage_and_call").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("set_transient_storage").unwrap(); + ExtBuilder::default().build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + // Call contracts with storage values within the limit. + // Caller and Callee contracts each set a transient storage value of size 100. + assert_ok!(builder::call(addr_caller) + .data((100u32, 100u32, &addr_callee).encode()) + .build(),); + + // Call a contract with a storage value that is too large. + // Limit exceeded in the caller contract. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data((4u32 * 1024u32, 200u32, &addr_callee).encode()) + .build(), + >::OutOfTransientStorage, + ); - // Re-Instantiate after termination. - assert_ok!(builder::instantiate(code_hash).build()); + // Call a contract with a storage value that is too large. + // Limit exceeded in the callee contract. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data((50u32, 4 * 1024u32, &addr_callee).encode()) + .build(), + >::ContractTrapped + ); + }); +} - // Trie ids shouldn't match or we might have a collision - assert_ne!(trie_id, get_contract(&addr).trie_id); - }); - } +#[test] +fn deploy_and_call_other_contract() { + let (caller_wasm, _caller_code_hash) = compile_module("caller_contract").unwrap(); + let (callee_wasm, callee_code_hash) = compile_module("return_with_data").unwrap(); - #[test] - fn storage_work() { - let (code, _code_hash) = compile_module("storage").unwrap(); + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let min_balance = Contracts::min_balance(); - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) + // Create + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr: caller_addr, account_id: caller_account } = + builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(100_000) .build_and_unwrap_contract(); - builder::bare_call(addr).build_and_unwrap_result(); - }); - } + let callee_addr = create2( + &caller_addr, + &callee_wasm, + &[0, 1, 34, 51, 68, 85, 102, 119], // hard coded in wasm + &[0u8; 32], + ); + let callee_account = ::AddressMapper::to_account_id(&callee_addr); - #[test] - fn storage_max_value_limit() { - let (wasm, _code_hash) = compile_module("storage_size").unwrap(); + Contracts::upload_code(RuntimeOrigin::signed(ALICE), callee_wasm, deposit_limit::()) + .unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(30_000) - .build_and_unwrap_contract(); - get_contract(&addr); - - // Call contract with allowed storage value. - assert_ok!(builder::call(addr) - .gas_limit(GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2)) // we are copying a huge buffer - .data(limits::PAYLOAD_BYTES.encode()) - .build()); - - // Call contract with too large a storage value. - assert_err_ignore_postinfo!( - builder::call(addr).data((limits::PAYLOAD_BYTES + 1).encode()).build(), - Error::::ValueTooLarge, - ); - }); - } + // Drop previous events + initialize_block(2); - #[test] - fn transient_storage_work() { - let (code, _code_hash) = compile_module("transient_storage").unwrap(); + // Call BOB contract, which attempts to instantiate and call the callee contract and + // makes various assertions on the results from those calls. + assert_ok!(builder::call(caller_addr).data(callee_code_hash.as_ref().to_vec()).build()); - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: callee_account.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: callee_account.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: callee_account.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: caller_account.clone(), + to: callee_account.clone(), + amount: 32768 // hardcoded in wasm + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: caller_addr, + contract: callee_addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: caller_account.clone(), + to: callee_account.clone(), + amount: 32768, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(caller_account.clone()), + contract: callee_addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: caller_addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndHeld { + from: ALICE_ADDR, + to: callee_addr, + amount: test_utils::contract_info_storage_deposit(&callee_addr), + } + ), + topics: vec![], + }, + ] + ); + }); +} - builder::bare_call(addr).build_and_unwrap_result(); - }); - } +#[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(); - #[test] - fn transient_storage_limit_in_call() { - let (wasm_caller, _code_hash_caller) = - compile_module("create_transient_storage_and_call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("set_transient_storage").unwrap(); - ExtBuilder::default().build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); - - // Call contracts with storage values within the limit. - // Caller and Callee contracts each set a transient storage value of size 100. - assert_ok!(builder::call(addr_caller) - .data((100u32, 100u32, &addr_callee).encode()) - .build(),); - - // Call a contract with a storage value that is too large. - // Limit exceeded in the caller contract. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((4u32 * 1024u32, 200u32, &addr_callee).encode()) - .build(), - >::OutOfTransientStorage, - ); + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(300_000) + .build_and_unwrap_contract(); - // Call a contract with a storage value that is too large. - // Limit exceeded in the callee contract. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((50u32, 4 * 1024u32, &addr_callee).encode()) - .build(), - >::ContractTrapped - ); - }); - } + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_wasm)) + .value(100_000) + .build_and_unwrap_contract(); - #[test] - fn deploy_and_call_other_contract() { - let (caller_wasm, _caller_code_hash) = compile_module("caller_contract").unwrap(); - let (callee_wasm, callee_code_hash) = compile_module("return_with_data").unwrap(); + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 0u64, 0u64).encode()) + .build()); + }); +} - ExtBuilder::default().existential_deposit(1).build().execute_with(|| { - let min_balance = Contracts::min_balance(); +#[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(); - // Create - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr: caller_addr, account_id: caller_account } = - builder::bare_instantiate(Code::Upload(caller_wasm)) - .value(100_000) - .build_and_unwrap_contract(); + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let callee_addr = create2( - &caller_addr, - &callee_wasm, - &[0, 1, 34, 51, 68, 85, 102, 119], // hard coded in wasm - &[0u8; 32], - ); - let callee_account = ::AddressMapper::to_account_id(&callee_addr); + // Instantiate the 'caller' + let Contract { addr: caller_addr, .. } = + builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(300_000) + .build_and_unwrap_contract(); - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - callee_wasm, - deposit_limit::(), - ) - .unwrap(); + // Instantiate the 'callee' + let Contract { addr: callee_addr, .. } = + builder::bare_instantiate(Code::Upload(callee_wasm)) + .value(100_000) + .build_and_unwrap_contract(); - // Drop previous events - initialize_block(2); + // fails, not enough weight + assert_err!( + builder::bare_call(caller_addr) + .value(1337) + .data((callee_addr, 100u64, 100u64).encode()) + .build() + .result, + Error::::ContractTrapped, + ); - // Call BOB contract, which attempts to instantiate and call the callee contract and - // makes various assertions on the results from those calls. - assert_ok!(builder::call(caller_addr).data(callee_code_hash.as_ref().to_vec()).build()); + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 500_000_000u64, 100_000u64).encode()) + .build()); + }); +} - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: callee_account.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: callee_account.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: callee_account.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: caller_account.clone(), - to: callee_account.clone(), - amount: 32768 // hardcoded in wasm - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: caller_addr, - contract: callee_addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: caller_account.clone(), - to: callee_account.clone(), - amount: 32768, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(caller_account.clone()), - contract: callee_addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: caller_addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndHeld { - from: ALICE_ADDR, - to: callee_addr, - amount: test_utils::contract_info_storage_deposit(&callee_addr), - } - ), - topics: vec![], - }, - ] - ); - }); - } +#[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(); - #[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(); + ExtBuilder::default().existential_deposit(500).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - 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 'caller' - let Contract { addr: caller_addr, .. } = - 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_pvm)) + .value(100_000) + .build_and_unwrap_contract(); - assert_ok!(builder::call(caller_addr) + // Delegate call will write 1 storage and deposit of 2 (1 item) + 32 (bytes) is required. + // Fails, not enough deposit + assert_err!( + builder::bare_call(caller_addr) .value(1337) - .data(callee_code_hash.as_ref().to_vec()) - .build()); - }); - } - - #[test] - fn transfer_expendable_cannot_kill_account() { - let (wasm, _code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + .data((callee_addr, 33u64).encode()) + .build() + .result, + Error::::StorageDepositLimitExhausted, + ); - // Instantiate the BOB contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(1_000) - .build_and_unwrap_contract(); + assert_ok!(builder::call(caller_addr) + .value(1337) + .data((callee_addr, 34u64).encode()) + .build()); + }); +} - // Check that the BOB contract has been instantiated. - get_contract(&addr); +#[test] +fn transfer_expendable_cannot_kill_account() { + let (wasm, _code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let account = ::AddressMapper::to_account_id(&addr); - let total_balance = ::Currency::total_balance(&account); + // Instantiate the BOB contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(1_000) + .build_and_unwrap_contract(); - assert_eq!( - test_utils::get_balance_on_hold( - &HoldReason::StorageDepositReserve.into(), - &account - ), - test_utils::contract_info_storage_deposit(&addr) - ); + // Check that the BOB contract has been instantiated. + get_contract(&addr); - // Some ot the total balance is held, so it can't be transferred. - assert_err!( - <::Currency as Mutate>::transfer( - &account, - &ALICE, - total_balance, - Preservation::Expendable, - ), - TokenError::FundsUnavailable, - ); + let account = ::AddressMapper::to_account_id(&addr); + let total_balance = ::Currency::total_balance(&account); - assert_eq!(::Currency::total_balance(&account), total_balance); - }); - } + assert_eq!( + test_utils::get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account), + test_utils::contract_info_storage_deposit(&addr) + ); - #[test] - fn cannot_self_destruct_through_draining() { - let (wasm, _code_hash) = compile_module("drain").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let value = 1_000; - let min_balance = Contracts::min_balance(); + // Some ot the total balance is held, so it can't be transferred. + assert_err!( + <::Currency as Mutate>::transfer( + &account, + &ALICE, + total_balance, + Preservation::Expendable, + ), + TokenError::FundsUnavailable, + ); - // Instantiate the BOB contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(value) - .build_and_unwrap_contract(); - let account = ::AddressMapper::to_account_id(&addr); + assert_eq!(::Currency::total_balance(&account), total_balance); + }); +} - // Check that the BOB contract has been instantiated. - get_contract(&addr); +#[test] +fn cannot_self_destruct_through_draining() { + let (wasm, _code_hash) = compile_module("drain").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let value = 1_000; + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(value) + .build_and_unwrap_contract(); + let account = ::AddressMapper::to_account_id(&addr); + + // Check that the BOB contract has been instantiated. + get_contract(&addr); + + // Call BOB which makes it send all funds to the zero address + // The contract code asserts that the transfer fails with the correct error code + assert_ok!(builder::call(addr).build()); + + // Make sure the account wasn't remove by sending all free balance away. + assert_eq!( + ::Currency::total_balance(&account), + value + test_utils::contract_info_storage_deposit(&addr) + min_balance, + ); + }); +} - // Call BOB which makes it send all funds to the zero address - // The contract code asserts that the transfer fails with the correct error code - assert_ok!(builder::call(addr).build()); +#[test] +fn cannot_self_destruct_through_storage_refund_after_price_change() { + let (wasm, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let contract = builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + let info_deposit = test_utils::contract_info_storage_deposit(&contract.addr); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit); + assert_eq!(get_contract(&contract.addr).extra_deposit(), 0); + assert_eq!( + ::Currency::total_balance(&contract.account_id), + info_deposit + min_balance + ); - // Make sure the account wasn't remove by sending all free balance away. - assert_eq!( - ::Currency::total_balance(&account), - value + test_utils::contract_info_storage_deposit(&addr) + min_balance, - ); - }); - } + // Create 100 bytes of storage with a price of per byte and a single storage item of + // price 2 + assert_ok!(builder::call(contract.addr).data(100u32.to_le_bytes().to_vec()).build()); + assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit + 102); + + // Increase the byte price and trigger a refund. This should not have any influence + // because the removal is pro rata and exactly those 100 bytes should have been + // removed. + DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); + assert_ok!(builder::call(contract.addr).data(0u32.to_le_bytes().to_vec()).build()); + + // Make sure the account wasn't removed by the refund + assert_eq!( + ::Currency::total_balance(&contract.account_id), + get_contract(&contract.addr).total_deposit() + min_balance, + ); + assert_eq!(get_contract(&contract.addr).extra_deposit(), 2); + }); +} - #[test] - fn cannot_self_destruct_through_storage_refund_after_price_change() { - let (wasm, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); +#[test] +fn cannot_self_destruct_while_live() { + let (wasm, _code_hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the BOB contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_contract(); + + // Check that the BOB contract has been instantiated. + get_contract(&addr); + + // Call BOB with input data, forcing it make a recursive call to itself to + // self-destruct, resulting in a trap. + assert_err_ignore_postinfo!( + builder::call(addr).data(vec![0]).build(), + Error::::ContractTrapped, + ); - // Instantiate the BOB contract. - let contract = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - let info_deposit = test_utils::contract_info_storage_deposit(&contract.addr); + // Check that BOB is still there. + get_contract(&addr); + }); +} - // Check that the contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit); - assert_eq!(get_contract(&contract.addr).extra_deposit(), 0); - assert_eq!( - ::Currency::total_balance(&contract.account_id), - info_deposit + min_balance - ); +#[test] +fn self_destruct_works() { + let (wasm, code_hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(1_000).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&DJANGO_FALLBACK, 1_000_000); + let min_balance = Contracts::min_balance(); - // Create 100 bytes of storage with a price of per byte and a single storage item of - // price 2 - assert_ok!(builder::call(contract.addr).data(100u32.to_le_bytes().to_vec()).build()); - assert_eq!(get_contract(&contract.addr).total_deposit(), info_deposit + 102); + // Instantiate the BOB contract. + let contract = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_contract(); - // Increase the byte price and trigger a refund. This should not have any influence - // because the removal is pro rata and exactly those 100 bytes should have been - // removed. - DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); - assert_ok!(builder::call(contract.addr).data(0u32.to_le_bytes().to_vec()).build()); + // Check that the BOB contract has been instantiated. + let _ = get_contract(&contract.addr); - // Make sure the account wasn't removed by the refund - assert_eq!( - ::Currency::total_balance(&contract.account_id), - get_contract(&contract.addr).total_deposit() + min_balance, - ); - assert_eq!(get_contract(&contract.addr).extra_deposit(), 2); - }); - } + let info_deposit = test_utils::contract_info_storage_deposit(&contract.addr); - #[test] - fn cannot_self_destruct_while_live() { - let (wasm, _code_hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Drop all previous events + initialize_block(2); - // Instantiate the BOB contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(100_000) - .build_and_unwrap_contract(); + // Call BOB without input data which triggers termination. + assert_matches!(builder::call(contract.addr).build(), Ok(_)); - // Check that the BOB contract has been instantiated. - get_contract(&addr); + // Check that code is still there but refcount dropped to zero. + assert_refcount!(&code_hash, 0); - // Call BOB with input data, forcing it make a recursive call to itself to - // self-destruct, resulting in a trap. - assert_err_ignore_postinfo!( - builder::call(addr).data(vec![0]).build(), - Error::::ContractTrapped, - ); + // Check that account is gone + assert!(get_contract_checked(&contract.addr).is_none()); + assert_eq!(::Currency::total_balance(&contract.account_id), 0); - // Check that BOB is still there. - get_contract(&addr); - }); - } + // Check that the beneficiary (django) got remaining balance. + assert_eq!( + ::Currency::free_balance(DJANGO_FALLBACK), + 1_000_000 + 100_000 + min_balance + ); - #[test] - fn self_destruct_works() { - let (wasm, code_hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(1_000).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(Ð_DJANGO, 1_000_000); - let min_balance = Contracts::min_balance(); + // Check that the Alice is missing Django's benefit. Within ALICE's total balance + // there's also the code upload deposit held. + assert_eq!( + ::Currency::total_balance(&ALICE), + 1_000_000 - (100_000 + min_balance) + ); - // Instantiate the BOB contract. - let contract = builder::bare_instantiate(Code::Upload(wasm)) - .value(100_000) - .build_and_unwrap_contract(); + pretty_assertions::assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Terminated { + contract: contract.addr, + beneficiary: DJANGO_ADDR, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: contract.addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndReleased { + from: contract.addr, + to: ALICE_ADDR, + amount: info_deposit, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::KilledAccount { + account: contract.account_id.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: contract.account_id.clone(), + to: DJANGO_FALLBACK, + amount: 100_000 + min_balance, + }), + topics: vec![], + }, + ], + ); + }); +} - // Check that the BOB contract has been instantiated. - let _ = get_contract(&contract.addr); +// This tests that one contract cannot prevent another from self-destructing by sending it +// additional funds after it has been drained. +#[test] +fn destroy_contract_and_transfer_funds() { + let (callee_wasm, callee_code_hash) = compile_module("self_destruct").unwrap(); + let (caller_wasm, _caller_code_hash) = compile_module("destroy_and_transfer").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + // Create code hash for bob to instantiate + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + callee_wasm.clone(), + deposit_limit::(), + ) + .unwrap(); + + // This deploys the BOB contract, which in turn deploys the CHARLIE contract during + // construction. + let Contract { addr: addr_bob, .. } = builder::bare_instantiate(Code::Upload(caller_wasm)) + .value(200_000) + .data(callee_code_hash.as_ref().to_vec()) + .build_and_unwrap_contract(); + + // Check that the CHARLIE contract has been instantiated. + let salt = [47; 32]; // hard coded in fixture. + let addr_charlie = create2(&addr_bob, &callee_wasm, &[], &salt); + get_contract(&addr_charlie); + + // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. + assert_ok!(builder::call(addr_bob).data(addr_charlie.encode()).build()); + + // Check that CHARLIE has moved on to the great beyond (ie. died). + assert!(get_contract_checked(&addr_charlie).is_none()); + }); +} - let info_deposit = test_utils::contract_info_storage_deposit(&contract.addr); +#[test] +fn cannot_self_destruct_in_constructor() { + let (wasm, _) = compile_module("self_destructing_constructor").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Drop all previous events - initialize_block(2); + // Fail to instantiate the BOB because the constructor calls seal_terminate. + assert_err_ignore_postinfo!( + builder::instantiate_with_code(wasm).value(100_000).build(), + Error::::TerminatedInConstructor, + ); + }); +} - // Call BOB without input data which triggers termination. - assert_matches!(builder::call(contract.addr).build(), Ok(_)); +#[test] +fn crypto_hashes() { + let (wasm, _code_hash) = compile_module("crypto_hashes").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the CRYPTO_HASHES contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_contract(); + // Perform the call. + let input = b"_DEAD_BEEF"; + use sp_io::hashing::*; + // Wraps a hash function into a more dynamic form usable for testing. + macro_rules! dyn_hash_fn { + ($name:ident) => { + Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice()) + }; + } + // All hash functions and their associated output byte lengths. + let test_cases: &[(Box Box<[u8]>>, usize)] = &[ + (dyn_hash_fn!(sha2_256), 32), + (dyn_hash_fn!(keccak_256), 32), + (dyn_hash_fn!(blake2_256), 32), + (dyn_hash_fn!(blake2_128), 16), + ]; + // Test the given hash functions for the input: "_DEAD_BEEF" + for (n, (hash_fn, expected_size)) in test_cases.iter().enumerate() { + // We offset data in the contract tables by 1. + let mut params = vec![(n + 1) as u8]; + params.extend_from_slice(input); + let result = builder::bare_call(addr).data(params).build_and_unwrap_result(); + assert!(!result.did_revert()); + let expected = hash_fn(input.as_ref()); + assert_eq!(&result.data[..*expected_size], &*expected); + } + }) +} - // Check that code is still there but refcount dropped to zero. - assert_refcount!(&code_hash, 0); +#[test] +fn transfer_return_code() { + let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let contract = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + // Contract has only the minimal balance so any transfer will fail. + ::Currency::set_balance(&contract.account_id, min_balance); + let result = builder::bare_call(contract.addr).build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + }); +} - // Check that account is gone - assert!(get_contract_checked(&contract.addr).is_none()); - assert_eq!(::Currency::total_balance(&contract.account_id), 0); +#[test] +fn call_return_code() { + use test_utils::u256_bytes; + + let (caller_code, _caller_hash) = compile_module("call_return_code").unwrap(); + let (callee_code, _callee_hash) = compile_module("ok_trap_revert").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + + let bob = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + // Contract calls into Django which is no valid contract + // This will be a balance transfer into a new account + // with more than the contract has which will make the transfer fail + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&DJANGO_ADDR) + .iter() + .chain(&u256_bytes(min_balance * 200)) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // 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( + AsRef::<[u8]>::as_ref(&DJANGO_ADDR) + .iter() + .chain(&u256_bytes(55)) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::Success); + assert_eq!(test_utils::get_balance(&DJANGO_FALLBACK), 55 + min_balance); + + let django = builder::bare_instantiate(Code::Upload(callee_code)) + .origin(RuntimeOrigin::signed(CHARLIE)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + // Sending more than the contract has will make the transfer fail. + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&django.addr) + .iter() + .chain(&u256_bytes(min_balance * 300)) + .chain(&0u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // Contract has enough balance but callee reverts because "1" is passed. + ::Currency::set_balance(&bob.account_id, min_balance + 1000); + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&django.addr) + .iter() + .chain(&u256_bytes(5)) + .chain(&1u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeReverted); - // Check that the beneficiary (django) got remaining balance. - assert_eq!( - ::Currency::free_balance(ETH_DJANGO), - 1_000_000 + 100_000 + min_balance - ); + // Contract has enough balance but callee traps because "2" is passed. + let result = builder::bare_call(bob.addr) + .data( + AsRef::<[u8]>::as_ref(&django.addr) + .iter() + .chain(&u256_bytes(5)) + .chain(&2u32.to_le_bytes()) + .cloned() + .collect(), + ) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); + }); +} - // Check that the Alice is missing Django's benefit. Within ALICE's total balance - // there's also the code upload deposit held. - assert_eq!( - ::Currency::total_balance(&ALICE), - 1_000_000 - (100_000 + min_balance) - ); +#[test] +fn instantiate_return_code() { + let (caller_code, _caller_hash) = compile_module("instantiate_return_code").unwrap(); + let (callee_code, callee_hash) = compile_module("ok_trap_revert").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + let callee_hash = callee_hash.as_ref().to_vec(); + + assert_ok!(builder::instantiate_with_code(callee_code).value(min_balance * 100).build()); + + let contract = builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + // Contract has only the minimal balance so any transfer will fail. + ::Currency::set_balance(&contract.account_id, min_balance); + let result = builder::bare_call(contract.addr) + .data(callee_hash.clone()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::TransferFailed); + + // 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); + + // Contract has enough balance but callee reverts because "1" is passed. + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeReverted); + + // Contract has enough balance but callee traps because "2" is passed. + let result = builder::bare_call(contract.addr) + .data(callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect()) + .build_and_unwrap_result(); + assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); + }); +} - pretty_assertions::assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Terminated { - contract: contract.addr, - beneficiary: DJANGO_ADDR, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: contract.addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndReleased { - from: contract.addr, - to: ALICE_ADDR, - amount: info_deposit, - } - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::KilledAccount { - account: contract.account_id.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: contract.account_id.clone(), - to: ETH_DJANGO, - amount: 100_000 + min_balance, - }), - topics: vec![], - }, - ], - ); - }); - } +#[test] +fn disabled_chain_extension_errors_on_call() { + let (code, _hash) = compile_module("chain_extension").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let contract = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + TestExtension::disable(); + assert_err_ignore_postinfo!( + builder::call(contract.addr).data(vec![7u8; 8]).build(), + Error::::NoChainExtension, + ); + }); +} - // This tests that one contract cannot prevent another from self-destructing by sending it - // additional funds after it has been drained. - #[test] - fn destroy_contract_and_transfer_funds() { - let (callee_wasm, callee_code_hash) = compile_module("self_destruct").unwrap(); - let (caller_wasm, _caller_code_hash) = compile_module("destroy_and_transfer").unwrap(); +#[test] +fn chain_extension_works() { + let (code, _hash) = compile_module("chain_extension").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let contract = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + // 0 = read input buffer and pass it through as output + let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); + let result = builder::bare_call(contract.addr).data(input.clone()).build(); + assert_eq!(TestExtension::last_seen_buffer(), input); + assert_eq!(result.result.unwrap().data, input); + + // 1 = treat inputs as integer primitives and store the supplied integers + builder::bare_call(contract.addr) + .data(ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into()) + .build_and_unwrap_result(); + assert_eq!(TestExtension::last_seen_input_len(), 4); + + // 2 = charge some extra weight (amount supplied in the fifth byte) + let result = builder::bare_call(contract.addr) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &0u32.encode() }.into()) + .build(); + assert_ok!(result.result); + let gas_consumed = result.gas_consumed; + let result = builder::bare_call(contract.addr) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &42u32.encode() }.into()) + .build(); + assert_ok!(result.result); + assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); + let result = builder::bare_call(contract.addr) + .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &95u32.encode() }.into()) + .build(); + assert_ok!(result.result); + assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); + + // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer + let result = builder::bare_call(contract.addr) + .data(ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into()) + .build_and_unwrap_result(); + assert_eq!(result.flags, ReturnFlags::REVERT); + assert_eq!(result.data, vec![42, 99]); + + // diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer + // We set the MSB part to 1 (instead of 0) which routes the request into the second + // extension + let result = builder::bare_call(contract.addr) + .data(ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into()) + .build_and_unwrap_result(); + assert_eq!(result.flags, ReturnFlags::REVERT); + assert_eq!(result.data, vec![0x4B, 0x1D]); + + // Diverging to third chain extension that is disabled + // We set the MSB part to 2 (instead of 0) which routes the request into the third + // extension + assert_err_ignore_postinfo!( + builder::call(contract.addr) + .data(ExtensionInput { extension_id: 2, func_id: 0, extra: &[] }.into()) + .build(), + Error::::NoChainExtension, + ); + }); +} - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - // Create code hash for bob to instantiate - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - callee_wasm.clone(), - deposit_limit::(), - ) - .unwrap(); +#[test] +fn chain_extension_temp_storage_works() { + let (code, _hash) = compile_module("chain_extension_temp_storage").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let contract = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); + + // Call func 0 and func 1 back to back. + let stop_recursion = 0u8; + let mut input: Vec = ExtensionInput { extension_id: 3, func_id: 0, extra: &[] }.into(); + input.extend_from_slice( + ExtensionInput { extension_id: 3, func_id: 1, extra: &[stop_recursion] } + .to_vec() + .as_ref(), + ); - // This deploys the BOB contract, which in turn deploys the CHARLIE contract during - // construction. - let Contract { addr: addr_bob, .. } = - builder::bare_instantiate(Code::Upload(caller_wasm)) - .value(200_000) - .data(callee_code_hash.as_ref().to_vec()) - .build_and_unwrap_contract(); + assert_ok!(builder::bare_call(contract.addr).data(input.clone()).build().result); + }) +} - // Check that the CHARLIE contract has been instantiated. - let salt = [47; 32]; // hard coded in fixture. - let addr_charlie = create2(&addr_bob, &callee_wasm, &[], &salt); - get_contract(&addr_charlie); +#[test] +fn lazy_removal_works() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. - assert_ok!(builder::call(addr_bob).data(addr_charlie.encode()).build()); + let contract = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // Check that CHARLIE has moved on to the great beyond (ie. died). - assert!(get_contract_checked(&addr_charlie).is_none()); - }); - } + let info = get_contract(&contract.addr); + let trie = &info.child_trie_info(); - #[test] - fn cannot_self_destruct_in_constructor() { - let (wasm, _) = compile_module("self_destructing_constructor").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Put value into the contracts child trie + child::put(trie, &[99], &42); - // Fail to instantiate the BOB because the constructor calls seal_terminate. - assert_err_ignore_postinfo!( - builder::instantiate_with_code(wasm).value(100_000).build(), - Error::::TerminatedInConstructor, - ); - }); - } + // Terminate the contract + assert_ok!(builder::call(contract.addr).build()); - #[test] - fn crypto_hashes() { - let (wasm, _code_hash) = compile_module("crypto_hashes").unwrap(); + // Contract info should be gone + assert!(!>::contains_key(&contract.addr)); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // But value should be still there as the lazy removal did not run, yet. + assert_matches!(child::get(trie, &[99]), Some(42)); - // Instantiate the CRYPTO_HASHES contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(100_000) - .build_and_unwrap_contract(); - // Perform the call. - let input = b"_DEAD_BEEF"; - use sp_io::hashing::*; - // Wraps a hash function into a more dynamic form usable for testing. - macro_rules! dyn_hash_fn { - ($name:ident) => { - Box::new(|input| $name(input).as_ref().to_vec().into_boxed_slice()) - }; - } - // All hash functions and their associated output byte lengths. - let test_cases: &[(Box Box<[u8]>>, usize)] = &[ - (dyn_hash_fn!(sha2_256), 32), - (dyn_hash_fn!(keccak_256), 32), - (dyn_hash_fn!(blake2_256), 32), - (dyn_hash_fn!(blake2_128), 16), - ]; - // Test the given hash functions for the input: "_DEAD_BEEF" - for (n, (hash_fn, expected_size)) in test_cases.iter().enumerate() { - // We offset data in the contract tables by 1. - let mut params = vec![(n + 1) as u8]; - params.extend_from_slice(input); - let result = builder::bare_call(addr).data(params).build_and_unwrap_result(); - assert!(!result.did_revert()); - let expected = hash_fn(input.as_ref()); - assert_eq!(&result.data[..*expected_size], &*expected); - } - }) - } + // Run the lazy removal + Contracts::on_idle(System::block_number(), Weight::MAX); + + // Value should be gone now + assert_matches!(child::get::(trie, &[99]), None); + }); +} - #[test] - fn transfer_return_code() { - let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); +#[test] +fn lazy_batch_removal_works() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let mut tries: Vec = vec![]; - let contract = builder::bare_instantiate(Code::Upload(wasm)) + for i in 0..3u8 { + let contract = builder::bare_instantiate(Code::Upload(code.clone())) .value(min_balance * 100) + .salt(Some([i; 32])) .build_and_unwrap_contract(); - // Contract has only the minimal balance so any transfer will fail. - ::Currency::set_balance(&contract.account_id, min_balance); - let result = builder::bare_call(contract.addr).build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); - }); - } + let info = get_contract(&contract.addr); + let trie = &info.child_trie_info(); - #[test] - fn call_return_code() { - use test_utils::u256_bytes; + // Put value into the contracts child trie + child::put(trie, &[99], &42); - let (caller_code, _caller_hash) = compile_module("call_return_code").unwrap(); - let (callee_code, _callee_hash) = compile_module("ok_trap_revert").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + // Terminate the contract. Contract info should be gone, but value should be still + // there as the lazy removal did not run, yet. + assert_ok!(builder::call(contract.addr).build()); - let bob = builder::bare_instantiate(Code::Upload(caller_code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + assert!(!>::contains_key(&contract.addr)); + assert_matches!(child::get(trie, &[99]), Some(42)); - // Contract calls into Django which is no valid contract - // This will be a balance transfer into a new account - // with more than the contract has which will make the transfer fail - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&DJANGO_ADDR) - .iter() - .chain(&u256_bytes(min_balance * 200)) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); + tries.push(trie.clone()) + } - // 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); + // Run single lazy removal + Contracts::on_idle(System::block_number(), Weight::MAX); - // Sending at least the minimum balance should result in success but - // no code called. - assert_eq!(test_utils::get_balance(Ð_DJANGO), 0); - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&DJANGO_ADDR) - .iter() - .chain(&u256_bytes(55)) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::Success); - assert_eq!(test_utils::get_balance(Ð_DJANGO), 55); + // The single lazy removal should have removed all queued tries + for trie in tries.iter() { + assert_matches!(child::get::(trie, &[99]), None); + } + }); +} - let django = builder::bare_instantiate(Code::Upload(callee_code)) - .origin(RuntimeOrigin::signed(CHARLIE)) - .value(min_balance * 100) - .build_and_unwrap_contract(); +#[test] +fn lazy_removal_partial_remove_works() { + let (code, _hash) = compile_module("self_destruct").unwrap(); - // Sending more than the contract has will make the transfer fail. - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&django.addr) - .iter() - .chain(&u256_bytes(min_balance * 300)) - .chain(&0u32.to_le_bytes()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); + // We create a contract with some extra keys above the weight limit + let extra_keys = 7u32; + let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); + let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); + let vals: Vec<_> = (0..max_keys + extra_keys) + .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) + .collect(); - // Contract has enough balance but callee reverts because "1" is passed. - ::Currency::set_balance(&bob.account_id, min_balance + 1000); - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&django.addr) - .iter() - .chain(&u256_bytes(5)) - .chain(&1u32.to_le_bytes()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeReverted); + let mut ext = ExtBuilder::default().existential_deposit(50).build(); - // Contract has enough balance but callee traps because "2" is passed. - let result = builder::bare_call(bob.addr) - .data( - AsRef::<[u8]>::as_ref(&django.addr) - .iter() - .chain(&u256_bytes(5)) - .chain(&2u32.to_le_bytes()) - .cloned() - .collect(), - ) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); - }); - } + let trie = ext.execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - #[test] - fn instantiate_return_code() { - let (caller_code, _caller_hash) = compile_module("instantiate_return_code").unwrap(); - let (callee_code, callee_hash) = compile_module("ok_trap_revert").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - let callee_hash = callee_hash.as_ref().to_vec(); - - assert_ok!(builder::instantiate_with_code(callee_code) - .value(min_balance * 100) - .build()); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - let contract = builder::bare_instantiate(Code::Upload(caller_code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + let info = get_contract(&addr); - // Contract has only the minimal balance so any transfer will fail. - ::Currency::set_balance(&contract.account_id, min_balance); - let result = builder::bare_call(contract.addr) - .data(callee_hash.clone()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::TransferFailed); + // Put value into the contracts child trie + for val in &vals { + info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); + } + >::insert(&addr, info.clone()); - // 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); + // Terminate the contract + assert_ok!(builder::call(addr).build()); - // Contract has enough balance but callee reverts because "1" is passed. - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeReverted); + // Contract info should be gone + assert!(!>::contains_key(&addr)); - // Contract has enough balance but callee traps because "2" is passed. - let result = builder::bare_call(contract.addr) - .data(callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect()) - .build_and_unwrap_result(); - assert_return_code!(result, RuntimeReturnCode::CalleeTrapped); - }); - } + let trie = info.child_trie_info(); - #[test] - fn disabled_chain_extension_errors_on_call() { - let (code, _hash) = compile_module("chain_extension").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let contract = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); - TestExtension::disable(); - assert_err_ignore_postinfo!( - builder::call(contract.addr).data(vec![7u8; 8]).build(), - Error::::NoChainExtension, - ); - }); - } + // But value should be still there as the lazy removal did not run, yet. + for val in &vals { + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); + } - #[test] - fn chain_extension_works() { - let (code, _hash) = compile_module("chain_extension").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let contract = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + trie.clone() + }); - // 0 = read input buffer and pass it through as output - let input: Vec = - ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); - let result = builder::bare_call(contract.addr).data(input.clone()).build(); - assert_eq!(TestExtension::last_seen_buffer(), input); - assert_eq!(result.result.unwrap().data, input); + // The lazy removal limit only applies to the backend but not to the overlay. + // This commits all keys from the overlay to the backend. + ext.commit_all().unwrap(); - // 1 = treat inputs as integer primitives and store the supplied integers - builder::bare_call(contract.addr) - .data(ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into()) - .build_and_unwrap_result(); - assert_eq!(TestExtension::last_seen_input_len(), 4); - - // 2 = charge some extra weight (amount supplied in the fifth byte) - let result = builder::bare_call(contract.addr) - .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &0u32.encode() }.into()) - .build(); - assert_ok!(result.result); - let gas_consumed = result.gas_consumed; - let result = builder::bare_call(contract.addr) - .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &42u32.encode() }.into()) - .build(); - assert_ok!(result.result); - assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); - let result = builder::bare_call(contract.addr) - .data(ExtensionInput { extension_id: 0, func_id: 2, extra: &95u32.encode() }.into()) - .build(); - assert_ok!(result.result); - assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); - - // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer - let result = builder::bare_call(contract.addr) - .data(ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into()) - .build_and_unwrap_result(); - assert_eq!(result.flags, ReturnFlags::REVERT); - assert_eq!(result.data, vec![42, 99]); - - // diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer - // We set the MSB part to 1 (instead of 0) which routes the request into the second - // extension - let result = builder::bare_call(contract.addr) - .data(ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into()) - .build_and_unwrap_result(); - assert_eq!(result.flags, ReturnFlags::REVERT); - assert_eq!(result.data, vec![0x4B, 0x1D]); - - // Diverging to third chain extension that is disabled - // We set the MSB part to 2 (instead of 0) which routes the request into the third - // extension - assert_err_ignore_postinfo!( - builder::call(contract.addr) - .data(ExtensionInput { extension_id: 2, func_id: 0, extra: &[] }.into()) - .build(), - Error::::NoChainExtension, - ); - }); - } + ext.execute_with(|| { + // Run the lazy removal + ContractInfo::::process_deletion_queue_batch(&mut meter); - #[test] - fn chain_extension_temp_storage_works() { - let (code, _hash) = compile_module("chain_extension_temp_storage").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let contract = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + // Weight should be exhausted because we could not even delete all keys + assert!(!meter.can_consume(weight_per_key)); - // Call func 0 and func 1 back to back. - let stop_recursion = 0u8; - let mut input: Vec = - ExtensionInput { extension_id: 3, func_id: 0, extra: &[] }.into(); - input.extend_from_slice( - ExtensionInput { extension_id: 3, func_id: 1, extra: &[stop_recursion] } - .to_vec() - .as_ref(), - ); + let mut num_deleted = 0u32; + let mut num_remaining = 0u32; - assert_ok!(builder::bare_call(contract.addr).data(input.clone()).build().result); - }) - } + for val in &vals { + match child::get::(&trie, &blake2_256(&val.0)) { + None => num_deleted += 1, + Some(x) if x == val.1 => num_remaining += 1, + Some(_) => panic!("Unexpected value in contract storage"), + } + } - #[test] - fn lazy_removal_works() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + // All but one key is removed + assert_eq!(num_deleted + num_remaining, vals.len() as u32); + assert_eq!(num_deleted, max_keys); + assert_eq!(num_remaining, extra_keys); + }); +} - let contract = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); +#[test] +fn lazy_removal_does_no_run_on_low_remaining_weight() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let info = get_contract(&contract.addr); - let trie = &info.child_trie_info(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // Put value into the contracts child trie - child::put(trie, &[99], &42); + let info = get_contract(&addr); + let trie = &info.child_trie_info(); - // Terminate the contract - assert_ok!(builder::call(contract.addr).build()); + // Put value into the contracts child trie + child::put(trie, &[99], &42); - // Contract info should be gone - assert!(!>::contains_key(&contract.addr)); + // Terminate the contract + assert_ok!(builder::call(addr).build()); - // But value should be still there as the lazy removal did not run, yet. - assert_matches!(child::get(trie, &[99]), Some(42)); + // Contract info should be gone + assert!(!>::contains_key(&addr)); - // Run the lazy removal - Contracts::on_idle(System::block_number(), Weight::MAX); + // But value should be still there as the lazy removal did not run, yet. + assert_matches!(child::get(trie, &[99]), Some(42)); - // Value should be gone now - assert_matches!(child::get::(trie, &[99]), None); - }); - } + // Assign a remaining weight which is too low for a successful deletion of the contract + let low_remaining_weight = + <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); - #[test] - fn lazy_batch_removal_works() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let mut tries: Vec = vec![]; - - for i in 0..3u8 { - let contract = builder::bare_instantiate(Code::Upload(code.clone())) - .value(min_balance * 100) - .salt(Some([i; 32])) - .build_and_unwrap_contract(); + // Run the lazy removal + Contracts::on_idle(System::block_number(), low_remaining_weight); - let info = get_contract(&contract.addr); - let trie = &info.child_trie_info(); + // Value should still be there, since remaining weight was too low for removal + assert_matches!(child::get::(trie, &[99]), Some(42)); - // Put value into the contracts child trie - child::put(trie, &[99], &42); + // Run the lazy removal while deletion_queue is not full + Contracts::on_initialize(System::block_number()); - // Terminate the contract. Contract info should be gone, but value should be still - // there as the lazy removal did not run, yet. - assert_ok!(builder::call(contract.addr).build()); + // Value should still be there, since deletion_queue was not full + assert_matches!(child::get::(trie, &[99]), Some(42)); - assert!(!>::contains_key(&contract.addr)); - assert_matches!(child::get(trie, &[99]), Some(42)); + // Run on_idle with max remaining weight, this should remove the value + Contracts::on_idle(System::block_number(), Weight::MAX); - tries.push(trie.clone()) - } + // Value should be gone + assert_matches!(child::get::(trie, &[99]), None); + }); +} - // Run single lazy removal - Contracts::on_idle(System::block_number(), Weight::MAX); +#[test] +fn lazy_removal_does_not_use_all_weight() { + let (code, _hash) = compile_module("self_destruct").unwrap(); - // The single lazy removal should have removed all queued tries - for trie in tries.iter() { - assert_matches!(child::get::(trie, &[99]), None); - } - }); - } + let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); + let mut ext = ExtBuilder::default().existential_deposit(50).build(); + + let (trie, vals, weight_per_key) = ext.execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - #[test] - fn lazy_removal_partial_remove_works() { - let (code, _hash) = compile_module("self_destruct").unwrap(); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // We create a contract with some extra keys above the weight limit - let extra_keys = 7u32; - let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); + let info = get_contract(&addr); let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); - let vals: Vec<_> = (0..max_keys + extra_keys) + assert!(max_keys > 0); + + // We create a contract with one less storage item than we can remove within the limit + let vals: Vec<_> = (0..max_keys - 1) .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) .collect(); - let mut ext = ExtBuilder::default().existential_deposit(50).build(); - - let trie = ext.execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); - - let info = get_contract(&addr); - - // Put value into the contracts child trie - for val in &vals { - info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); - } - >::insert(&addr, info.clone()); + // Put value into the contracts child trie + for val in &vals { + info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); + } + >::insert(&addr, info.clone()); - // Terminate the contract - assert_ok!(builder::call(addr).build()); + // Terminate the contract + assert_ok!(builder::call(addr).build()); - // Contract info should be gone - assert!(!>::contains_key(&addr)); + // Contract info should be gone + assert!(!>::contains_key(&addr)); - let trie = info.child_trie_info(); + let trie = info.child_trie_info(); - // But value should be still there as the lazy removal did not run, yet. - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); - } + // But value should be still there as the lazy removal did not run, yet. + for val in &vals { + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); + } - trie.clone() - }); + (trie, vals, weight_per_key) + }); - // The lazy removal limit only applies to the backend but not to the overlay. - // This commits all keys from the overlay to the backend. - ext.commit_all().unwrap(); + // The lazy removal limit only applies to the backend but not to the overlay. + // This commits all keys from the overlay to the backend. + ext.commit_all().unwrap(); - ext.execute_with(|| { - // Run the lazy removal - ContractInfo::::process_deletion_queue_batch(&mut meter); + ext.execute_with(|| { + // Run the lazy removal + ContractInfo::::process_deletion_queue_batch(&mut meter); + let base_weight = + <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); + assert_eq!(meter.consumed(), weight_per_key.mul(vals.len() as _) + base_weight); - // Weight should be exhausted because we could not even delete all keys - assert!(!meter.can_consume(weight_per_key)); + // All the keys are removed + for val in vals { + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); + } + }); +} - let mut num_deleted = 0u32; - let mut num_remaining = 0u32; +#[test] +fn deletion_queue_ring_buffer_overflow() { + let (code, _hash) = compile_module("self_destruct").unwrap(); + let mut ext = ExtBuilder::default().existential_deposit(50).build(); - for val in &vals { - match child::get::(&trie, &blake2_256(&val.0)) { - None => num_deleted += 1, - Some(x) if x == val.1 => num_remaining += 1, - Some(_) => panic!("Unexpected value in contract storage"), - } - } + // setup the deletion queue with custom counters + ext.execute_with(|| { + let queue = DeletionQueueManager::from_test_values(u32::MAX - 1, u32::MAX - 1); + >::set(queue); + }); - // All but one key is removed - assert_eq!(num_deleted + num_remaining, vals.len() as u32); - assert_eq!(num_deleted, max_keys); - assert_eq!(num_remaining, extra_keys); - }); - } + // commit the changes to the storage + ext.commit_all().unwrap(); - #[test] - fn lazy_removal_does_no_run_on_low_remaining_weight() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + ext.execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let mut tries: Vec = vec![]; - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + // add 3 contracts to the deletion queue + for i in 0..3u8 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) .value(min_balance * 100) + .salt(Some([i; 32])) .build_and_unwrap_contract(); let info = get_contract(&addr); @@ -1899,669 +2096,816 @@ mod run_tests { // Put value into the contracts child trie child::put(trie, &[99], &42); - // Terminate the contract + // Terminate the contract. Contract info should be gone, but value should be still + // there as the lazy removal did not run, yet. assert_ok!(builder::call(addr).build()); - // Contract info should be gone assert!(!>::contains_key(&addr)); - - // But value should be still there as the lazy removal did not run, yet. assert_matches!(child::get(trie, &[99]), Some(42)); - // Assign a remaining weight which is too low for a successful deletion of the contract - let low_remaining_weight = - <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); - - // Run the lazy removal - Contracts::on_idle(System::block_number(), low_remaining_weight); + tries.push(trie.clone()) + } - // Value should still be there, since remaining weight was too low for removal - assert_matches!(child::get::(trie, &[99]), Some(42)); + // Run single lazy removal + Contracts::on_idle(System::block_number(), Weight::MAX); - // Run the lazy removal while deletion_queue is not full - Contracts::on_initialize(System::block_number()); + // The single lazy removal should have removed all queued tries + for trie in tries.iter() { + assert_matches!(child::get::(trie, &[99]), None); + } - // Value should still be there, since deletion_queue was not full - assert_matches!(child::get::(trie, &[99]), Some(42)); + // insert and delete counter values should go from u32::MAX - 1 to 1 + assert_eq!(>::get().as_test_tuple(), (1, 1)); + }) +} +#[test] +fn refcounter() { + let (wasm, code_hash) = compile_module("self_destruct").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Create two contracts with the same code and check that they do in fact share it. + let Contract { addr: addr0, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) + .value(min_balance * 100) + .salt(Some([0; 32])) + .build_and_unwrap_contract(); + let Contract { addr: addr1, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) + .value(min_balance * 100) + .salt(Some([1; 32])) + .build_and_unwrap_contract(); + assert_refcount!(code_hash, 2); + + // Sharing should also work with the usual instantiate call + let Contract { addr: addr2, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .value(min_balance * 100) + .salt(Some([2; 32])) + .build_and_unwrap_contract(); + assert_refcount!(code_hash, 3); + + // Terminating one contract should decrement the refcount + assert_ok!(builder::call(addr0).build()); + assert_refcount!(code_hash, 2); + + // remove another one + assert_ok!(builder::call(addr1).build()); + assert_refcount!(code_hash, 1); + + // Pristine code should still be there + PristineCode::::get(code_hash).unwrap(); + + // remove the last contract + assert_ok!(builder::call(addr2).build()); + assert_refcount!(code_hash, 0); + + // refcount is `0` but code should still exists because it needs to be removed manually + assert!(crate::PristineCode::::contains_key(&code_hash)); + }); +} - // Run on_idle with max remaining weight, this should remove the value - Contracts::on_idle(System::block_number(), Weight::MAX); +#[test] +fn debug_message_works() { + let (wasm, _code_hash) = compile_module("debug_message_works").unwrap(); - // Value should be gone - assert_matches!(child::get::(trie, &[99]), None); - }); - } + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_contract(); + let result = builder::bare_call(addr).debug(DebugInfo::UnsafeDebug).build(); - #[test] - fn lazy_removal_does_not_use_all_weight() { - let (code, _hash) = compile_module("self_destruct").unwrap(); + assert_matches!(result.result, Ok(_)); + assert_eq!(std::str::from_utf8(&result.debug_message).unwrap(), "Hello World!"); + }); +} - let mut meter = WeightMeter::with_limit(Weight::from_parts(5_000_000_000, 100 * 1024)); - let mut ext = ExtBuilder::default().existential_deposit(50).build(); +#[test] +fn debug_message_logging_disabled() { + let (wasm, _code_hash) = compile_module("debug_message_logging_disabled").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_contract(); + // the dispatchables always run without debugging + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr, + 0, + GAS_LIMIT, + deposit_limit::(), + vec![] + )); + }); +} - let (trie, vals, weight_per_key) = ext.execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); +#[test] +fn debug_message_invalid_utf8() { + let (wasm, _code_hash) = compile_module("debug_message_invalid_utf8").unwrap(); + + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(30_000) + .build_and_unwrap_contract(); + let result = builder::bare_call(addr).debug(DebugInfo::UnsafeDebug).build(); + assert_ok!(result.result); + assert!(result.debug_message.is_empty()); + }); +} - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) +#[test] +fn gas_estimation_for_subcalls() { + let (caller_code, _caller_hash) = compile_module("call_with_limit").unwrap(); + let (call_runtime_code, _caller_hash) = compile_module("call_runtime").unwrap(); + let (dummy_code, _callee_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 2_000 * min_balance); + + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(caller_code)) .value(min_balance * 100) .build_and_unwrap_contract(); - let info = get_contract(&addr); - let (weight_per_key, max_keys) = ContractInfo::::deletion_budget(&meter); - assert!(max_keys > 0); + let Contract { addr: addr_dummy, .. } = builder::bare_instantiate(Code::Upload(dummy_code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // We create a contract with one less storage item than we can remove within the limit - let vals: Vec<_> = (0..max_keys - 1) - .map(|i| (blake2_256(&i.encode()), (i as u32), (i as u32).encode())) - .collect(); + let Contract { addr: addr_call_runtime, .. } = + builder::bare_instantiate(Code::Upload(call_runtime_code)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // Put value into the contracts child trie - for val in &vals { - info.write(&Key::Fix(val.0), Some(val.2.clone()), None, false).unwrap(); - } - >::insert(&addr, info.clone()); + // Run the test for all of those weight limits for the subcall + let weights = [ + Weight::zero(), + GAS_LIMIT, + GAS_LIMIT * 2, + GAS_LIMIT / 5, + Weight::from_parts(0, GAS_LIMIT.proof_size()), + Weight::from_parts(GAS_LIMIT.ref_time(), 0), + ]; - // Terminate the contract - assert_ok!(builder::call(addr).build()); + // This call is passed to the sub call in order to create a large `required_weight` + let runtime_call = RuntimeCall::Dummy(pallet_dummy::Call::overestimate_pre_charge { + pre_charge: Weight::from_parts(10_000_000_000, 512 * 1024), + actual_weight: Weight::from_parts(1, 1), + }) + .encode(); - // Contract info should be gone - assert!(!>::contains_key(&addr)); + // Encodes which contract should be sub called with which input + let sub_calls: [(&[u8], Vec<_>, bool); 2] = [ + (addr_dummy.as_ref(), vec![], false), + (addr_call_runtime.as_ref(), runtime_call, true), + ]; - let trie = info.child_trie_info(); + for weight in weights { + for (sub_addr, sub_input, out_of_gas_in_subcall) in &sub_calls { + let input: Vec = sub_addr + .iter() + .cloned() + .chain(weight.ref_time().to_le_bytes()) + .chain(weight.proof_size().to_le_bytes()) + .chain(sub_input.clone()) + .collect(); + + // Call in order to determine the gas that is required for this call + let result_orig = builder::bare_call(addr_caller).data(input.clone()).build(); + assert_ok!(&result_orig.result); + + // If the out of gas happens in the subcall the caller contract + // will just trap. Otherwise we would need to forward an error + // code to signal that the sub contract ran out of gas. + let error: DispatchError = if *out_of_gas_in_subcall { + assert!(result_orig.gas_required.all_gt(result_orig.gas_consumed)); + >::ContractTrapped.into() + } else { + assert_eq!(result_orig.gas_required, result_orig.gas_consumed); + >::OutOfGas.into() + }; - // But value should be still there as the lazy removal did not run, yet. - for val in &vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); + // 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()) + .data(input.clone()) + .build(); + assert_ok!(&result.result); + + // 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()) + .data(input.clone()) + .build(); + assert_err!(result.result, error); + + // 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()) + .data(input.clone()) + .build(); + assert_err!(result.result, error); } + } + }); +} - (trie, vals, weight_per_key) - }); +#[test] +fn gas_estimation_call_runtime() { + let (caller_code, _caller_hash) = compile_module("call_runtime").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - // The lazy removal limit only applies to the backend but not to the overlay. - // This commits all keys from the overlay to the backend. - ext.commit_all().unwrap(); + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .salt(Some([0; 32])) + .build_and_unwrap_contract(); - ext.execute_with(|| { - // Run the lazy removal - ContractInfo::::process_deletion_queue_batch(&mut meter); - let base_weight = - <::WeightInfo as WeightInfo>::on_process_deletion_queue_batch(); - assert_eq!(meter.consumed(), weight_per_key.mul(vals.len() as _) + base_weight); - - // All the keys are removed - for val in vals { - assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); - } + // Call something trivial with a huge gas limit so that we can observe the effects + // of pre-charging. This should create a difference between consumed and required. + let call = RuntimeCall::Dummy(pallet_dummy::Call::overestimate_pre_charge { + pre_charge: Weight::from_parts(10_000_000, 1_000), + actual_weight: Weight::from_parts(100, 100), }); - } + let result = builder::bare_call(addr_caller).data(call.encode()).build(); + // contract encodes the result of the dispatch runtime + let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); + assert_eq!(outcome, 0); + assert!(result.gas_required.all_gt(result.gas_consumed)); + + // Make the same call using the required gas. Should succeed. + assert_ok!( + builder::bare_call(addr_caller) + .gas_limit(result.gas_required) + .data(call.encode()) + .build() + .result + ); + }); +} - #[test] - fn deletion_queue_ring_buffer_overflow() { - let (code, _hash) = compile_module("self_destruct").unwrap(); - let mut ext = ExtBuilder::default().existential_deposit(50).build(); +#[test] +fn call_runtime_reentrancy_guarded() { + let (caller_code, _caller_hash) = compile_module("call_runtime").unwrap(); + let (callee_code, _callee_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); + + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(caller_code)) + .value(min_balance * 100) + .salt(Some([0; 32])) + .build_and_unwrap_contract(); - // setup the deletion queue with custom counters - ext.execute_with(|| { - let queue = DeletionQueueManager::from_test_values(u32::MAX - 1, u32::MAX - 1); - >::set(queue); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(callee_code)) + .value(min_balance * 100) + .salt(Some([1; 32])) + .build_and_unwrap_contract(); + + // Call pallet_revive call() dispatchable + let call = RuntimeCall::Contracts(crate::Call::call { + dest: addr_callee, + value: 0, + gas_limit: GAS_LIMIT / 3, + storage_deposit_limit: deposit_limit::(), + data: vec![], }); - // commit the changes to the storage - ext.commit_all().unwrap(); + // Call runtime to re-enter back to contracts engine by + // calling dummy contract + let result = builder::bare_call(addr_caller).data(call.encode()).build_and_unwrap_result(); + // Call to runtime should fail because of the re-entrancy guard + assert_return_code!(result, RuntimeReturnCode::CallRuntimeFailed); + }); +} - ext.execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let mut tries: Vec = vec![]; - - // add 3 contracts to the deletion queue - for i in 0..3u8 { - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) - .value(min_balance * 100) - .salt(Some([i; 32])) - .build_and_unwrap_contract(); +#[test] +fn ecdsa_recover() { + let (wasm, _code_hash) = compile_module("ecdsa_recover").unwrap(); - let info = get_contract(&addr); - let trie = &info.child_trie_info(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Put value into the contracts child trie - child::put(trie, &[99], &42); + // Instantiate the ecdsa_recover contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_contract(); - // Terminate the contract. Contract info should be gone, but value should be still - // there as the lazy removal did not run, yet. - assert_ok!(builder::call(addr).build()); + #[rustfmt::skip] + let signature: [u8; 65] = [ + 161, 234, 203, 74, 147, 96, 51, 212, 5, 174, 231, 9, 142, 48, 137, 201, + 162, 118, 192, 67, 239, 16, 71, 216, 125, 86, 167, 139, 70, 7, 86, 241, + 33, 87, 154, 251, 81, 29, 160, 4, 176, 239, 88, 211, 244, 232, 232, 52, + 211, 234, 100, 115, 230, 47, 80, 44, 152, 166, 62, 50, 8, 13, 86, 175, + 28, + ]; + #[rustfmt::skip] + let message_hash: [u8; 32] = [ + 162, 28, 244, 179, 96, 76, 244, 178, 188, 83, 230, 248, 143, 106, 77, 117, + 239, 95, 244, 171, 65, 95, 62, 153, 174, 166, 182, 28, 130, 73, 196, 208 + ]; + #[rustfmt::skip] + const EXPECTED_COMPRESSED_PUBLIC_KEY: [u8; 33] = [ + 2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, + 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, + 152, + ]; + let mut params = vec![]; + params.extend_from_slice(&signature); + params.extend_from_slice(&message_hash); + assert!(params.len() == 65 + 32); + let result = builder::bare_call(addr).data(params).build_and_unwrap_result(); + assert!(!result.did_revert()); + assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY); + }) +} - assert!(!>::contains_key(&addr)); - assert_matches!(child::get(trie, &[99]), Some(42)); +#[test] +fn bare_instantiate_returns_events() { + let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + + let result = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .collect_events(CollectEvents::UnsafeCollect) + .build(); + + let events = result.events.unwrap(); + assert!(!events.is_empty()); + assert_eq!(events, System::events()); + }); +} - tries.push(trie.clone()) - } +#[test] +fn bare_instantiate_does_not_return_events() { + let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - // Run single lazy removal - Contracts::on_idle(System::block_number(), Weight::MAX); + let result = builder::bare_instantiate(Code::Upload(wasm)).value(min_balance * 100).build(); - // The single lazy removal should have removed all queued tries - for trie in tries.iter() { - assert_matches!(child::get::(trie, &[99]), None); - } + let events = result.events; + assert!(!System::events().is_empty()); + assert!(events.is_none()); + }); +} - // insert and delete counter values should go from u32::MAX - 1 to 1 - assert_eq!(>::get().as_test_tuple(), (1, 1)); - }) - } - #[test] - fn refcounter() { - let (wasm, code_hash) = compile_module("self_destruct").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Create two contracts with the same code and check that they do in fact share it. - let Contract { addr: addr0, .. } = - builder::bare_instantiate(Code::Upload(wasm.clone())) - .value(min_balance * 100) - .salt(Some([0; 32])) - .build_and_unwrap_contract(); - let Contract { addr: addr1, .. } = - builder::bare_instantiate(Code::Upload(wasm.clone())) - .value(min_balance * 100) - .salt(Some([1; 32])) - .build_and_unwrap_contract(); - assert_refcount!(code_hash, 2); - - // Sharing should also work with the usual instantiate call - let Contract { addr: addr2, .. } = builder::bare_instantiate(Code::Existing(code_hash)) - .value(min_balance * 100) - .salt(Some([2; 32])) - .build_and_unwrap_contract(); - assert_refcount!(code_hash, 3); +#[test] +fn bare_call_returns_events() { + let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - // Terminating one contract should decrement the refcount - assert_ok!(builder::call(addr0).build()); - assert_refcount!(code_hash, 2); + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - // remove another one - assert_ok!(builder::call(addr1).build()); - assert_refcount!(code_hash, 1); + let result = builder::bare_call(addr).collect_events(CollectEvents::UnsafeCollect).build(); - // Pristine code should still be there - PristineCode::::get(code_hash).unwrap(); + let events = result.events.unwrap(); + assert_return_code!(&result.result.unwrap(), RuntimeReturnCode::Success); + assert!(!events.is_empty()); + assert_eq!(events, System::events()); + }); +} - // remove the last contract - assert_ok!(builder::call(addr2).build()); - assert_refcount!(code_hash, 0); +#[test] +fn bare_call_does_not_return_events() { + let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let min_balance = Contracts::min_balance(); + let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - // refcount is `0` but code should still exists because it needs to be removed manually - assert!(crate::PristineCode::::contains_key(&code_hash)); - }); - } + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(min_balance * 100) + .build_and_unwrap_contract(); - #[test] - fn debug_message_works() { - let (wasm, _code_hash) = compile_module("debug_message_works").unwrap(); + let result = builder::bare_call(addr).build(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(30_000) - .build_and_unwrap_contract(); - let result = builder::bare_call(addr).debug(DebugInfo::UnsafeDebug).build(); + let events = result.events; + assert_return_code!(&result.result.unwrap(), RuntimeReturnCode::Success); + assert!(!System::events().is_empty()); + assert!(events.is_none()); + }); +} - assert_matches!(result.result, Ok(_)); - assert_eq!(std::str::from_utf8(&result.debug_message).unwrap(), "Hello World!"); - }); - } +#[test] +fn sr25519_verify() { + let (wasm, _code_hash) = compile_module("sr25519_verify").unwrap(); - #[test] - fn debug_message_logging_disabled() { - let (wasm, _code_hash) = compile_module("debug_message_logging_disabled").unwrap(); + ExtBuilder::default().existential_deposit(50).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(30_000) - .build_and_unwrap_contract(); - // the dispatchables always run without debugging - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr, - 0, - GAS_LIMIT, - deposit_limit::(), - vec![] - )); - }); - } + // Instantiate the sr25519_verify contract. + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(100_000) + .build_and_unwrap_contract(); - #[test] - fn debug_message_invalid_utf8() { - let (wasm, _code_hash) = compile_module("debug_message_invalid_utf8").unwrap(); + let call_with = |message: &[u8; 11]| { + // Alice's signature for "hello world" + #[rustfmt::skip] + let signature: [u8; 64] = [ + 184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247, + 99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83, + 85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90, 255, + 228, 54, 115, 63, 30, 207, 205, 131, + ]; - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(30_000) - .build_and_unwrap_contract(); - let result = builder::bare_call(addr).debug(DebugInfo::UnsafeDebug).build(); - assert_ok!(result.result); - assert!(result.debug_message.is_empty()); - }); - } + // Alice's public key + #[rustfmt::skip] + let public_key: [u8; 32] = [ + 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, + ]; - #[test] - fn gas_estimation_for_subcalls() { - let (caller_code, _caller_hash) = compile_module("call_with_limit").unwrap(); - let (call_runtime_code, _caller_hash) = compile_module("call_runtime").unwrap(); - let (dummy_code, _callee_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 2_000 * min_balance); - - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(caller_code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + let mut params = vec![]; + params.extend_from_slice(&signature); + params.extend_from_slice(&public_key); + params.extend_from_slice(message); - let Contract { addr: addr_dummy, .. } = - builder::bare_instantiate(Code::Upload(dummy_code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + builder::bare_call(addr).data(params).build_and_unwrap_result() + }; - let Contract { addr: addr_call_runtime, .. } = - builder::bare_instantiate(Code::Upload(call_runtime_code)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + // verification should succeed for "hello world" + assert_return_code!(call_with(&b"hello world"), RuntimeReturnCode::Success); - // Run the test for all of those weight limits for the subcall - let weights = [ - Weight::zero(), - GAS_LIMIT, - GAS_LIMIT * 2, - GAS_LIMIT / 5, - Weight::from_parts(0, GAS_LIMIT.proof_size()), - Weight::from_parts(GAS_LIMIT.ref_time(), 0), - ]; + // verification should fail for other messages + assert_return_code!(call_with(&b"hello worlD"), RuntimeReturnCode::Sr25519VerifyFailed); + }); +} - // This call is passed to the sub call in order to create a large `required_weight` - let runtime_call = RuntimeCall::Dummy(pallet_dummy::Call::overestimate_pre_charge { - pre_charge: Weight::from_parts(10_000_000_000, 512 * 1024), - actual_weight: Weight::from_parts(1, 1), - }) - .encode(); - - // Encodes which contract should be sub called with which input - let sub_calls: [(&[u8], Vec<_>, bool); 2] = [ - (addr_dummy.as_ref(), vec![], false), - (addr_call_runtime.as_ref(), runtime_call, true), - ]; +#[test] +fn failed_deposit_charge_should_roll_back_call() { + let (wasm_caller, _) = compile_module("call_runtime_and_call").unwrap(); + let (wasm_callee, _) = compile_module("store_call").unwrap(); + const ED: u64 = 200; - for weight in weights { - for (sub_addr, sub_input, out_of_gas_in_subcall) in &sub_calls { - let input: Vec = sub_addr - .iter() - .cloned() - .chain(weight.ref_time().to_le_bytes()) - .chain(weight.proof_size().to_le_bytes()) - .chain(sub_input.clone()) - .collect(); - - // Call in order to determine the gas that is required for this call - let result_orig = builder::bare_call(addr_caller).data(input.clone()).build(); - assert_ok!(&result_orig.result); - - // If the out of gas happens in the subcall the caller contract - // will just trap. Otherwise we would need to forward an error - // code to signal that the sub contract ran out of gas. - let error: DispatchError = if *out_of_gas_in_subcall { - assert!(result_orig.gas_required.all_gt(result_orig.gas_consumed)); - >::ContractTrapped.into() - } else { - assert_eq!(result_orig.gas_required, result_orig.gas_consumed); - >::OutOfGas.into() - }; - - // 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()) - .data(input.clone()) - .build(); - assert_ok!(&result.result); - - // 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()) - .data(input.clone()) - .build(); - assert_err!(result.result, error); - - // 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()) - .data(input.clone()) - .build(); - assert_err!(result.result, error); - } - } - }); - } + let execute = || { + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - #[test] - fn gas_estimation_call_runtime() { - let (caller_code, _caller_hash) = compile_module("call_runtime").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(caller_code)) - .value(min_balance * 100) - .salt(Some([0; 32])) + // Instantiate both contracts. + let caller = builder::bare_instantiate(Code::Upload(wasm_caller.clone())) + .build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee.clone())) .build_and_unwrap_contract(); - // Call something trivial with a huge gas limit so that we can observe the effects - // of pre-charging. This should create a difference between consumed and required. - let call = RuntimeCall::Dummy(pallet_dummy::Call::overestimate_pre_charge { - pre_charge: Weight::from_parts(10_000_000, 1_000), - actual_weight: Weight::from_parts(100, 100), + // Give caller proxy access to Alice. + assert_ok!(Proxy::add_proxy( + RuntimeOrigin::signed(ALICE), + caller.account_id.clone(), + (), + 0 + )); + + // Create a Proxy call that will attempt to transfer away Alice's balance. + let transfer_call = + Box::new(RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { + dest: CHARLIE, + value: pallet_balances::Pallet::::free_balance(&ALICE) - 2 * ED, + })); + + // Wrap the transfer call in a proxy call. + let transfer_proxy_call = RuntimeCall::Proxy(pallet_proxy::Call::proxy { + real: ALICE, + force_proxy_type: Some(()), + call: transfer_call, }); - let result = builder::bare_call(addr_caller).data(call.encode()).build(); - // contract encodes the result of the dispatch runtime - let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); - assert_eq!(outcome, 0); - assert!(result.gas_required.all_gt(result.gas_consumed)); - - // Make the same call using the required gas. Should succeed. - assert_ok!( - builder::bare_call(addr_caller) - .gas_limit(result.gas_required) - .data(call.encode()) - .build() - .result + + let data = ( + (ED - DepositPerItem::get()) as u32, // storage length + addr_callee, + transfer_proxy_call, ); - }); - } - #[test] - fn call_runtime_reentrancy_guarded() { - let (caller_code, _caller_hash) = compile_module("call_runtime").unwrap(); - let (callee_code, _callee_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); - let _ = ::Currency::set_balance(&CHARLIE, 1000 * min_balance); - - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(caller_code)) - .value(min_balance * 100) - .salt(Some([0; 32])) - .build_and_unwrap_contract(); + builder::call(caller.addr).data(data.encode()).build() + }) + }; - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(callee_code)) - .value(min_balance * 100) - .salt(Some([1; 32])) - .build_and_unwrap_contract(); + // With a low enough deposit per byte, the call should succeed. + let result = execute().unwrap(); - // Call pallet_revive call() dispatchable - let call = RuntimeCall::Contracts(crate::Call::call { - dest: addr_callee, - value: 0, - gas_limit: GAS_LIMIT / 3, - storage_deposit_limit: deposit_limit::(), - data: vec![], - }); + // Bump the deposit per byte to a high value to trigger a FundsUnavailable error. + DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 20); + assert_err_with_weight!(execute(), TokenError::FundsUnavailable, result.actual_weight); +} - // Call runtime to re-enter back to contracts engine by - // calling dummy contract - let result = - builder::bare_call(addr_caller).data(call.encode()).build_and_unwrap_result(); - // Call to runtime should fail because of the re-entrancy guard - assert_return_code!(result, RuntimeReturnCode::CallRuntimeFailed); - }); - } +#[test] +fn upload_code_works() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Drop previous events + initialize_block(2); + + assert!(!PristineCode::::contains_key(&code_hash)); + + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,)); + // Ensure the contract was stored and get expected deposit amount to be reserved. + let deposit_expected = expected_deposit(ensure_stored(code_hash)); + + assert_eq!( + System::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::CodeStored { + code_hash, + deposit_held: deposit_expected, + uploader: ALICE_ADDR + }), + topics: vec![], + },] + ); + }); +} - #[test] - fn ecdsa_recover() { - let (wasm, _code_hash) = compile_module("ecdsa_recover").unwrap(); +#[test] +fn upload_code_limit_too_low() { + let (wasm, _code_hash) = compile_module("dummy").unwrap(); + let deposit_expected = expected_deposit(wasm.len()); + let deposit_insufficient = deposit_expected.saturating_sub(1); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Instantiate the ecdsa_recover contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(100_000) - .build_and_unwrap_contract(); + // Drop previous events + initialize_block(2); - #[rustfmt::skip] - let signature: [u8; 65] = [ - 161, 234, 203, 74, 147, 96, 51, 212, 5, 174, 231, 9, 142, 48, 137, 201, - 162, 118, 192, 67, 239, 16, 71, 216, 125, 86, 167, 139, 70, 7, 86, 241, - 33, 87, 154, 251, 81, 29, 160, 4, 176, 239, 88, 211, 244, 232, 232, 52, - 211, 234, 100, 115, 230, 47, 80, 44, 152, 166, 62, 50, 8, 13, 86, 175, - 28, - ]; - #[rustfmt::skip] - let message_hash: [u8; 32] = [ - 162, 28, 244, 179, 96, 76, 244, 178, 188, 83, 230, 248, 143, 106, 77, 117, - 239, 95, 244, 171, 65, 95, 62, 153, 174, 166, 182, 28, 130, 73, 196, 208 - ]; - #[rustfmt::skip] - const EXPECTED_COMPRESSED_PUBLIC_KEY: [u8; 33] = [ - 2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, - 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, - 152, - ]; - let mut params = vec![]; - params.extend_from_slice(&signature); - params.extend_from_slice(&message_hash); - assert!(params.len() == 65 + 32); - let result = builder::bare_call(addr).data(params).build_and_unwrap_result(); - assert!(!result.did_revert()); - assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY); - }) - } + assert_noop!( + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, deposit_insufficient,), + >::StorageDepositLimitExhausted, + ); - #[test] - fn bare_instantiate_returns_events() { - let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + assert_eq!(System::events(), vec![]); + }); +} - let result = builder::bare_instantiate(Code::Upload(wasm)) - .value(min_balance * 100) - .collect_events(CollectEvents::UnsafeCollect) - .build(); +#[test] +fn upload_code_not_enough_balance() { + let (wasm, _code_hash) = compile_module("dummy").unwrap(); + let deposit_expected = expected_deposit(wasm.len()); + let deposit_insufficient = deposit_expected.saturating_sub(1); - let events = result.events.unwrap(); - assert!(!events.is_empty()); - assert_eq!(events, System::events()); - }); - } + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, deposit_insufficient); - #[test] - fn bare_instantiate_does_not_return_events() { - let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + // Drop previous events + initialize_block(2); - let result = - builder::bare_instantiate(Code::Upload(wasm)).value(min_balance * 100).build(); + assert_noop!( + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,), + >::StorageDepositNotEnoughFunds, + ); - let events = result.events; - assert!(!System::events().is_empty()); - assert!(events.is_none()); - }); - } + assert_eq!(System::events(), vec![]); + }); +} - #[test] - fn bare_call_returns_events() { - let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); +#[test] +fn remove_code_works() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(min_balance * 100) - .build_and_unwrap_contract(); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let result = - builder::bare_call(addr).collect_events(CollectEvents::UnsafeCollect).build(); + // Drop previous events + initialize_block(2); - let events = result.events.unwrap(); - assert_return_code!(&result.result.unwrap(), RuntimeReturnCode::Success); - assert!(!events.is_empty()); - assert_eq!(events, System::events()); - }); - } + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,)); + // Ensure the contract was stored and get expected deposit amount to be reserved. + let deposit_expected = expected_deposit(ensure_stored(code_hash)); - #[test] - fn bare_call_does_not_return_events() { - let (wasm, _code_hash) = compile_module("transfer_return_code").unwrap(); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let min_balance = Contracts::min_balance(); - let _ = ::Currency::set_balance(&ALICE, 1000 * min_balance); + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::CodeStored { + code_hash, + deposit_held: deposit_expected, + uploader: ALICE_ADDR + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::CodeRemoved { + code_hash, + deposit_released: deposit_expected, + remover: ALICE_ADDR + }), + topics: vec![], + }, + ] + ); + }); +} - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(min_balance * 100) - .build_and_unwrap_contract(); +#[test] +fn remove_code_wrong_origin() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); - let result = builder::bare_call(addr).build(); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let events = result.events; - assert_return_code!(&result.result.unwrap(), RuntimeReturnCode::Success); - assert!(!System::events().is_empty()); - assert!(events.is_none()); - }); - } + // Drop previous events + initialize_block(2); - #[test] - fn sr25519_verify() { - let (wasm, _code_hash) = compile_module("sr25519_verify").unwrap(); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,)); + // Ensure the contract was stored and get expected deposit amount to be reserved. + let deposit_expected = expected_deposit(ensure_stored(code_hash)); - ExtBuilder::default().existential_deposit(50).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + assert_noop!( + Contracts::remove_code(RuntimeOrigin::signed(BOB), code_hash), + sp_runtime::traits::BadOrigin, + ); - // Instantiate the sr25519_verify contract. - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) - .value(100_000) - .build_and_unwrap_contract(); + assert_eq!( + System::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::CodeStored { + code_hash, + deposit_held: deposit_expected, + uploader: ALICE_ADDR + }), + topics: vec![], + },] + ); + }); +} - let call_with = |message: &[u8; 11]| { - // Alice's signature for "hello world" - #[rustfmt::skip] - let signature: [u8; 64] = [ - 184, 49, 74, 238, 78, 165, 102, 252, 22, 92, 156, 176, 124, 118, 168, 116, 247, - 99, 0, 94, 2, 45, 9, 170, 73, 222, 182, 74, 60, 32, 75, 64, 98, 174, 69, 55, 83, - 85, 180, 98, 208, 75, 231, 57, 205, 62, 4, 105, 26, 136, 172, 17, 123, 99, 90, 255, - 228, 54, 115, 63, 30, 207, 205, 131, - ]; +#[test] +fn remove_code_in_use() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); - // Alice's public key - #[rustfmt::skip] - let public_key: [u8; 32] = [ - 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, - ]; + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let mut params = vec![]; - params.extend_from_slice(&signature); - params.extend_from_slice(&public_key); - params.extend_from_slice(message); + assert_ok!(builder::instantiate_with_code(wasm).build()); - builder::bare_call(addr).data(params).build_and_unwrap_result() - }; + // Drop previous events + initialize_block(2); - // verification should succeed for "hello world" - assert_return_code!(call_with(&b"hello world"), RuntimeReturnCode::Success); + assert_noop!( + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), + >::CodeInUse, + ); - // verification should fail for other messages - assert_return_code!(call_with(&b"hello worlD"), RuntimeReturnCode::Sr25519VerifyFailed); - }); - } + assert_eq!(System::events(), vec![]); + }); +} - #[test] - fn failed_deposit_charge_should_roll_back_call() { - let (wasm_caller, _) = compile_module("call_runtime_and_call").unwrap(); - let (wasm_callee, _) = compile_module("store_call").unwrap(); - const ED: u64 = 200; +#[test] +fn remove_code_not_found() { + let (_wasm, code_hash) = compile_module("dummy").unwrap(); - let execute = || { - ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Instantiate both contracts. - let caller = builder::bare_instantiate(Code::Upload(wasm_caller.clone())) - .build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee.clone())) - .build_and_unwrap_contract(); - - // Give caller proxy access to Alice. - assert_ok!(Proxy::add_proxy( - RuntimeOrigin::signed(ALICE), - caller.account_id.clone(), - (), - 0 - )); - - // Create a Proxy call that will attempt to transfer away Alice's balance. - let transfer_call = - Box::new(RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { - dest: CHARLIE, - value: pallet_balances::Pallet::::free_balance(&ALICE) - 2 * ED, - })); - - // Wrap the transfer call in a proxy call. - let transfer_proxy_call = RuntimeCall::Proxy(pallet_proxy::Call::proxy { - real: ALICE, - force_proxy_type: Some(()), - call: transfer_call, - }); - - let data = ( - (ED - DepositPerItem::get()) as u32, // storage length - addr_callee, - transfer_proxy_call, - ); + // Drop previous events + initialize_block(2); - builder::call(caller.addr).data(data.encode()).build() - }) - }; + assert_noop!( + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), + >::CodeNotFound, + ); - // With a low enough deposit per byte, the call should succeed. - let result = execute().unwrap(); + assert_eq!(System::events(), vec![]); + }); +} - // Bump the deposit per byte to a high value to trigger a FundsUnavailable error. - DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 20); - assert_err_with_weight!(execute(), TokenError::FundsUnavailable, result.actual_weight); - } +#[test] +fn instantiate_with_zero_balance_works() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); - #[test] - fn upload_code_works() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); + // Drop previous events + initialize_block(2); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + + // Ensure the contract was stored and get expected deposit amount to be reserved. + let deposit_expected = expected_deposit(ensure_stored(code_hash)); - // Drop previous events - initialize_block(2); + // Make sure the account exists even though no free balance was send + assert_eq!(::Currency::free_balance(&account_id), min_balance); + assert_eq!( + ::Currency::total_balance(&account_id), + min_balance + test_utils::contract_info_storage_deposit(&addr) + ); - assert!(!PristineCode::::contains_key(&code_hash)); + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::CodeStored { + code_hash, + deposit_held: deposit_expected, + uploader: ALICE_ADDR + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: account_id.clone(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: account_id.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id, + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: ALICE_ADDR, + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndHeld { + from: ALICE_ADDR, + to: addr, + amount: test_utils::contract_info_storage_deposit(&addr), + } + ), + topics: vec![], + }, + ] + ); + }); +} - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,)); - // Ensure the contract was stored and get expected deposit amount to be reserved. - let deposit_expected = expected_deposit(ensure_stored(code_hash)); +#[test] +fn instantiate_with_below_existential_deposit_works() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + let value = 50; + + // Drop previous events + initialize_block(2); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(wasm)) + .value(value) + .build_and_unwrap_contract(); + + // Ensure the contract was stored and get expected deposit amount to be reserved. + let deposit_expected = expected_deposit(ensure_stored(code_hash)); + // Make sure the account exists even though not enough free balance was send + assert_eq!(::Currency::free_balance(&account_id), min_balance + value); + assert_eq!( + ::Currency::total_balance(&account_id), + min_balance + value + test_utils::contract_info_storage_deposit(&addr) + ); - assert_eq!( - System::events(), - vec![EventRecord { + assert_eq!( + System::events(), + vec![ + EventRecord { phase: Phase::Initialization, event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash, @@ -2569,1831 +2913,1755 @@ mod run_tests { uploader: ALICE_ADDR }), topics: vec![], - },] - ); - }); - } + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: account_id.clone() + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { + account: account_id.clone(), + free_balance: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: min_balance, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: 50, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Instantiated { + deployer: ALICE_ADDR, + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndHeld { + from: ALICE_ADDR, + to: addr, + amount: test_utils::contract_info_storage_deposit(&addr), + } + ), + topics: vec![], + }, + ] + ); + }); +} - #[test] - fn upload_code_limit_too_low() { - let (wasm, _code_hash) = compile_module("dummy").unwrap(); - let deposit_expected = expected_deposit(wasm.len()); - let deposit_insufficient = deposit_expected.saturating_sub(1); +#[test] +fn storage_deposit_works() { + let (wasm, _code_hash) = compile_module("multi_store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + + let mut deposit = test_utils::contract_info_storage_deposit(&addr); + + // Drop previous events + initialize_block(2); + + // Create storage + assert_ok!(builder::call(addr).value(42).data((50u32, 20u32).encode()).build()); + // 4 is for creating 2 storage items + let charged0 = 4 + 50 + 20; + deposit += charged0; + assert_eq!(get_contract(&addr).total_deposit(), deposit); + + // Add more storage (but also remove some) + assert_ok!(builder::call(addr).data((100u32, 10u32).encode()).build()); + let charged1 = 50 - 10; + deposit += charged1; + assert_eq!(get_contract(&addr).total_deposit(), deposit); + + // Remove more storage (but also add some) + assert_ok!(builder::call(addr).data((10u32, 20u32).encode()).build()); + // -1 for numeric instability + let refunded0 = 90 - 10 - 1; + deposit -= refunded0; + assert_eq!(get_contract(&addr).total_deposit(), deposit); + + assert_eq!( + System::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { + from: ALICE, + to: account_id.clone(), + amount: 42, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndHeld { + from: ALICE_ADDR, + to: addr, + amount: charged0, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndHeld { + from: ALICE_ADDR, + to: addr, + amount: charged1, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts( + pallet_revive::Event::StorageDepositTransferredAndReleased { + from: addr, + to: ALICE_ADDR, + amount: refunded0, + } + ), + topics: vec![], + }, + ] + ); + }); +} - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); +#[test] +fn storage_deposit_callee_works() { + let (wasm_caller, _code_hash_caller) = compile_module("call").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, account_id } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + assert_ok!(builder::call(addr_caller).data((100u32, &addr_callee).encode()).build()); + + let callee = get_contract(&addr_callee); + let deposit = DepositPerByte::get() * 100 + DepositPerItem::get() * 1; + + assert_eq!(test_utils::get_balance(&account_id), min_balance); + assert_eq!( + callee.total_deposit(), + deposit + test_utils::contract_info_storage_deposit(&addr_callee) + ); + }); +} - // Drop previous events - initialize_block(2); +#[test] +fn set_code_extrinsic() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); + let (new_wasm, new_code_hash) = compile_module("crypto_hashes").unwrap(); - assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, deposit_insufficient,), - >::StorageDepositLimitExhausted, - ); + assert_ne!(code_hash, new_code_hash); - assert_eq!(System::events(), vec![]); - }); - } + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - #[test] - fn upload_code_not_enough_balance() { - let (wasm, _code_hash) = compile_module("dummy").unwrap(); - let deposit_expected = expected_deposit(wasm.len()); - let deposit_insufficient = deposit_expected.saturating_sub(1); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, deposit_insufficient); + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + new_wasm, + deposit_limit::(), + )); - // Drop previous events - initialize_block(2); + // Drop previous events + initialize_block(2); - assert_noop!( - Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,), - >::StorageDepositNotEnoughFunds, - ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - }); - } + // only root can execute this extrinsic + assert_noop!( + Contracts::set_code(RuntimeOrigin::signed(ALICE), addr, new_code_hash), + sp_runtime::traits::BadOrigin, + ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![]); + + // contract must exist + assert_noop!( + Contracts::set_code(RuntimeOrigin::root(), BOB_ADDR, new_code_hash), + >::ContractNotFound, + ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![]); + + // new code hash must exist + assert_noop!( + Contracts::set_code(RuntimeOrigin::root(), addr, Default::default()), + >::CodeNotFound, + ); + assert_eq!(get_contract(&addr).code_hash, code_hash); + assert_refcount!(&code_hash, 1); + assert_refcount!(&new_code_hash, 0); + assert_eq!(System::events(), vec![]); + + // successful call + assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr, new_code_hash)); + assert_eq!(get_contract(&addr).code_hash, new_code_hash); + assert_refcount!(&code_hash, 0); + assert_refcount!(&new_code_hash, 1); + assert_eq!( + System::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(pallet_revive::Event::ContractCodeUpdated { + contract: addr, + new_code_hash, + old_code_hash: code_hash, + }), + topics: vec![], + },] + ); + }); +} - #[test] - fn remove_code_works() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); +#[test] +fn slash_cannot_kill_account() { + let (wasm, _code_hash) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let value = 700; + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(wasm)) + .value(value) + .build_and_unwrap_contract(); - // Drop previous events - initialize_block(2); + // Drop previous events + initialize_block(2); - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,)); - // Ensure the contract was stored and get expected deposit amount to be reserved. - let deposit_expected = expected_deposit(ensure_stored(code_hash)); + let info_deposit = test_utils::contract_info_storage_deposit(&addr); - assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::CodeStored { - code_hash, - deposit_held: deposit_expected, - uploader: ALICE_ADDR - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::CodeRemoved { - code_hash, - deposit_released: deposit_expected, - remover: ALICE_ADDR - }), - topics: vec![], - }, - ] - ); - }); - } - - #[test] - fn remove_code_wrong_origin() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, 1_000,)); - // Ensure the contract was stored and get expected deposit amount to be reserved. - let deposit_expected = expected_deposit(ensure_stored(code_hash)); - - assert_noop!( - Contracts::remove_code(RuntimeOrigin::signed(BOB), code_hash), - sp_runtime::traits::BadOrigin, - ); - - assert_eq!( - System::events(), - vec![EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::CodeStored { - code_hash, - deposit_held: deposit_expected, - uploader: ALICE_ADDR - }), - topics: vec![], - },] - ); - }); - } - - #[test] - fn remove_code_in_use() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - assert_ok!(builder::instantiate_with_code(wasm).build()); - - // Drop previous events - initialize_block(2); - - assert_noop!( - Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), - >::CodeInUse, - ); - - assert_eq!(System::events(), vec![]); - }); - } - - #[test] - fn remove_code_not_found() { - let (_wasm, code_hash) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Drop previous events - initialize_block(2); - - assert_noop!( - Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), - >::CodeNotFound, - ); - - assert_eq!(System::events(), vec![]); - }); - } - - #[test] - fn instantiate_with_zero_balance_works() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Drop previous events - initialize_block(2); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - - // Ensure the contract was stored and get expected deposit amount to be reserved. - let deposit_expected = expected_deposit(ensure_stored(code_hash)); - - // Make sure the account exists even though no free balance was send - assert_eq!(::Currency::free_balance(&account_id), min_balance); - assert_eq!( - ::Currency::total_balance(&account_id), - min_balance + test_utils::contract_info_storage_deposit(&addr) - ); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::CodeStored { - code_hash, - deposit_held: deposit_expected, - uploader: ALICE_ADDR - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: account_id.clone(), - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: account_id.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id, - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: ALICE_ADDR, - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndHeld { - from: ALICE_ADDR, - to: addr, - amount: test_utils::contract_info_storage_deposit(&addr), - } - ), - topics: vec![], - }, - ] - ); - }); - } - - #[test] - fn instantiate_with_below_existential_deposit_works() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - let value = 50; - - // Drop previous events - initialize_block(2); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(wasm)) - .value(value) - .build_and_unwrap_contract(); - - // Ensure the contract was stored and get expected deposit amount to be reserved. - let deposit_expected = expected_deposit(ensure_stored(code_hash)); - // Make sure the account exists even though not enough free balance was send - assert_eq!(::Currency::free_balance(&account_id), min_balance + value); - assert_eq!( - ::Currency::total_balance(&account_id), - min_balance + value + test_utils::contract_info_storage_deposit(&addr) - ); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::CodeStored { - code_hash, - deposit_held: deposit_expected, - uploader: ALICE_ADDR - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::System(frame_system::Event::NewAccount { - account: account_id.clone() - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { - account: account_id.clone(), - free_balance: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: min_balance, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: 50, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Instantiated { - deployer: ALICE_ADDR, - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndHeld { - from: ALICE_ADDR, - to: addr, - amount: test_utils::contract_info_storage_deposit(&addr), - } - ), - topics: vec![], - }, - ] - ); - }); - } - - #[test] - fn storage_deposit_works() { - let (wasm, _code_hash) = compile_module("multi_store").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - - let mut deposit = test_utils::contract_info_storage_deposit(&addr); - - // Drop previous events - initialize_block(2); - - // Create storage - assert_ok!(builder::call(addr).value(42).data((50u32, 20u32).encode()).build()); - // 4 is for creating 2 storage items - let charged0 = 4 + 50 + 20; - deposit += charged0; - assert_eq!(get_contract(&addr).total_deposit(), deposit); - - // Add more storage (but also remove some) - assert_ok!(builder::call(addr).data((100u32, 10u32).encode()).build()); - let charged1 = 50 - 10; - deposit += charged1; - assert_eq!(get_contract(&addr).total_deposit(), deposit); - - // Remove more storage (but also add some) - assert_ok!(builder::call(addr).data((10u32, 20u32).encode()).build()); - // -1 for numeric instability - let refunded0 = 90 - 10 - 1; - deposit -= refunded0; - assert_eq!(get_contract(&addr).total_deposit(), deposit); - - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { - from: ALICE, - to: account_id.clone(), - amount: 42, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndHeld { - from: ALICE_ADDR, - to: addr, - amount: charged0, - } - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndHeld { - from: ALICE_ADDR, - to: addr, - amount: charged1, - } - ), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts( - pallet_revive::Event::StorageDepositTransferredAndReleased { - from: addr, - to: ALICE_ADDR, - amount: refunded0, - } - ), - topics: vec![], - }, - ] - ); - }); - } - - #[test] - fn storage_deposit_callee_works() { - let (wasm_caller, _code_hash_caller) = compile_module("call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); + assert_eq!( + test_utils::get_balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id), + info_deposit + ); - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, account_id } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + value + min_balance + ); - assert_ok!(builder::call(addr_caller).data((100u32, &addr_callee).encode()).build()); + // Try to destroy the account of the contract by slashing the total balance. + // The account does not get destroyed because slashing only affects the balance held + // under certain `reason`. Slashing can for example happen if the contract takes part + // in staking. + let _ = ::Currency::slash( + &HoldReason::StorageDepositReserve.into(), + &account_id, + ::Currency::total_balance(&account_id), + ); - let callee = get_contract(&addr_callee); - let deposit = DepositPerByte::get() * 100 + DepositPerItem::get() * 1; + // Slashing only removed the balance held. + assert_eq!(::Currency::total_balance(&account_id), value + min_balance); + }); +} - assert_eq!(test_utils::get_balance(&account_id), min_balance); - assert_eq!( - callee.total_deposit(), - deposit + test_utils::contract_info_storage_deposit(&addr_callee) - ); - }); - } +#[test] +fn contract_reverted() { + let (wasm, code_hash) = compile_module("return_with_data").unwrap(); - #[test] - fn set_code_extrinsic() { - let (wasm, code_hash) = compile_module("dummy").unwrap(); - let (new_wasm, new_code_hash) = compile_module("crypto_hashes").unwrap(); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let flags = ReturnFlags::REVERT; + let buffer = [4u8, 8, 15, 16, 23, 42]; + let input = (flags.bits(), buffer).encode(); - assert_ne!(code_hash, new_code_hash); + // We just upload the code for later use + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + deposit_limit::(), + )); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).data(input.clone()).build(), + >::ContractReverted, + ); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + builder::instantiate_with_code(wasm).data(input.clone()).build(), + >::ContractReverted, + ); - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + // Calling directly: revert leads to success but the flags indicate the error + // This is just a different way of transporting the error that allows the read out + // the `data` which is only there on success. Obviously, the contract isn't + // instantiated. + let result = builder::bare_instantiate(Code::Existing(code_hash)) + .data(input.clone()) + .build_and_unwrap_result(); + assert_eq!(result.result.flags, flags); + assert_eq!(result.result.data, buffer); + assert!(!>::contains_key(result.addr)); + + // Pass empty flags and therefore successfully instantiate the contract for later use. + let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .data(ReturnFlags::empty().bits().encode()) + .build_and_unwrap_contract(); + + // Calling extrinsic: revert leads to an error + assert_err_ignore_postinfo!( + builder::call(addr).data(input.clone()).build(), + >::ContractReverted, + ); - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - new_wasm, - deposit_limit::(), - )); + // Calling directly: revert leads to success but the flags indicate the error + let result = builder::bare_call(addr).data(input).build_and_unwrap_result(); + assert_eq!(result.flags, flags); + assert_eq!(result.data, buffer); + }); +} - // Drop previous events - initialize_block(2); +#[test] +fn set_code_hash() { + let (wasm, code_hash) = compile_module("set_code_hash").unwrap(); + let (new_wasm, new_code_hash) = compile_module("new_set_code_hash_contract").unwrap(); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // only root can execute this extrinsic - assert_noop!( - Contracts::set_code(RuntimeOrigin::signed(ALICE), addr, new_code_hash), - sp_runtime::traits::BadOrigin, - ); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - - // contract must exist - assert_noop!( - Contracts::set_code(RuntimeOrigin::root(), BOB_ADDR, new_code_hash), - >::ContractNotFound, - ); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - - // new code hash must exist - assert_noop!( - Contracts::set_code(RuntimeOrigin::root(), addr, Default::default()), - >::CodeNotFound, - ); - assert_eq!(get_contract(&addr).code_hash, code_hash); - assert_refcount!(&code_hash, 1); - assert_refcount!(&new_code_hash, 0); - assert_eq!(System::events(), vec![]); - - // successful call - assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr, new_code_hash)); - assert_eq!(get_contract(&addr).code_hash, new_code_hash); - assert_refcount!(&code_hash, 0); - assert_refcount!(&new_code_hash, 1); - assert_eq!( - System::events(), - vec![EventRecord { + // Instantiate the 'caller' + let Contract { addr: contract_addr, .. } = builder::bare_instantiate(Code::Upload(wasm)) + .value(300_000) + .build_and_unwrap_contract(); + // upload new code + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + new_wasm.clone(), + deposit_limit::(), + )); + + System::reset_events(); + + // First call sets new code_hash and returns 1 + let result = builder::bare_call(contract_addr) + .data(new_code_hash.as_ref().to_vec()) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); + assert_return_code!(result, 1); + + // Second calls new contract code that returns 2 + let result = builder::bare_call(contract_addr) + .debug(DebugInfo::UnsafeDebug) + .build_and_unwrap_result(); + assert_return_code!(result, 2); + + // Checking for the last event only + assert_eq!( + &System::events(), + &[ + EventRecord { phase: Phase::Initialization, - event: RuntimeEvent::Contracts(pallet_revive::Event::ContractCodeUpdated { - contract: addr, + event: RuntimeEvent::Contracts(crate::Event::ContractCodeUpdated { + contract: contract_addr, new_code_hash, old_code_hash: code_hash, }), topics: vec![], - },] - ); - }); - } - - #[test] - fn slash_cannot_kill_account() { - let (wasm, _code_hash) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let value = 700; - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - let Contract { addr, account_id } = builder::bare_instantiate(Code::Upload(wasm)) - .value(value) - .build_and_unwrap_contract(); + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: contract_addr, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::Contracts(crate::Event::Called { + caller: Origin::from_account_id(ALICE), + contract: contract_addr, + }), + topics: vec![], + }, + ], + ); + }); +} - // Drop previous events - initialize_block(2); +#[test] +fn storage_deposit_limit_is_enforced() { + let (wasm, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let min_balance = Contracts::min_balance(); + + // Setting insufficient storage_deposit should fail. + assert_err!( + builder::bare_instantiate(Code::Upload(wasm.clone())) + // expected deposit is 2 * ed + 3 for the call + .storage_deposit_limit((2 * min_balance + 3 - 1).into()) + .build() + .result, + >::StorageDepositLimitExhausted, + ); - let info_deposit = test_utils::contract_info_storage_deposit(&addr); + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - assert_eq!( - test_utils::get_balance_on_hold( - &HoldReason::StorageDepositReserve.into(), - &account_id - ), - info_deposit - ); + let info_deposit = test_utils::contract_info_storage_deposit(&addr); + // Check that the BOB contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + min_balance + ); - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + value + min_balance - ); + // Create 1 byte of storage with a price of per byte, + // setting insufficient deposit limit, as it requires 3 Balance: + // 2 for the item added + 1 for the new storage item. + assert_err_ignore_postinfo!( + builder::call(addr) + .storage_deposit_limit(2) + .data(1u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositLimitExhausted, + ); - // Try to destroy the account of the contract by slashing the total balance. - // The account does not get destroyed because slashing only affects the balance held - // under certain `reason`. Slashing can for example happen if the contract takes part - // in staking. - let _ = ::Currency::slash( - &HoldReason::StorageDepositReserve.into(), - &account_id, - ::Currency::total_balance(&account_id), - ); + // Create 1 byte of storage, should cost 3 Balance: + // 2 for the item added + 1 for the new storage item. + // Should pass as it fallbacks to DefaultDepositLimit. + assert_ok!(builder::call(addr) + .storage_deposit_limit(3) + .data(1u32.to_le_bytes().to_vec()) + .build()); + + // Use 4 more bytes of the storage for the same item, which requires 4 Balance. + // Should fail as DefaultDepositLimit is 3 and hence isn't enough. + assert_err_ignore_postinfo!( + builder::call(addr) + .storage_deposit_limit(3) + .data(5u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositLimitExhausted, + ); + }); +} - // Slashing only removed the balance held. - assert_eq!(::Currency::total_balance(&account_id), value + min_balance); - }); - } +#[test] +fn deposit_limit_in_nested_calls() { + let (wasm_caller, _code_hash_caller) = compile_module("create_storage_and_call").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + // Create 100 bytes of storage with a price of per byte + // This is 100 Balance + 2 Balance for the item + assert_ok!(builder::call(addr_callee) + .storage_deposit_limit(102) + .data(100u32.to_le_bytes().to_vec()) + .build()); + + // We do not remove any storage but add a storage item of 12 bytes in the caller + // contract. This would cost 12 + 2 = 14 Balance. + // The nested call doesn't get a special limit, which is set by passing 0 to it. + // This should fail as the specified parent's limit is less than the cost: 13 < + // 14. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .storage_deposit_limit(13) + .data((100u32, &addr_callee, U256::from(0u64)).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); - #[test] - fn contract_reverted() { - let (wasm, code_hash) = compile_module("return_with_data").unwrap(); + // Now we specify the parent's limit high enough to cover the caller's storage + // additions. However, we use a single byte more in the callee, hence the storage + // deposit should be 15 Balance. + // The nested call doesn't get a special limit, which is set by passing 0 to it. + // This should fail as the specified parent's limit is less than the cost: 14 + // < 15. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .storage_deposit_limit(14) + .data((101u32, &addr_callee, U256::from(0u64)).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let flags = ReturnFlags::REVERT; - let buffer = [4u8, 8, 15, 16, 23, 42]; - let input = (flags.bits(), buffer).encode(); + // Now we specify the parent's limit high enough to cover both the caller's and callee's + // storage additions. However, we set a special deposit limit of 1 Balance for the + // 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, + ); - // We just upload the code for later use - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm.clone(), - deposit_limit::(), - )); + // 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 + // making the test case fail. We don't set a special limit for the nested call here. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .storage_deposit_limit(0) + .data((87u32, &addr_callee, U256::from(0u64)).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); - // Calling extrinsic: revert leads to an error - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).data(input.clone()).build(), - >::ContractReverted, - ); + let _ = ::Currency::set_balance(&ALICE, 511); - // Calling extrinsic: revert leads to an error - assert_err_ignore_postinfo!( - builder::instantiate_with_code(wasm).data(input.clone()).build(), - >::ContractReverted, - ); + // 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, + ); - // Calling directly: revert leads to success but the flags indicate the error - // This is just a different way of transporting the error that allows the read out - // the `data` which is only there on success. Obviously, the contract isn't - // instantiated. - let result = builder::bare_instantiate(Code::Existing(code_hash)) - .data(input.clone()) - .build_and_unwrap_result(); - assert_eq!(result.result.flags, flags); - assert_eq!(result.result.data, buffer); - assert!(!>::contains_key(result.addr)); + // 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 + // enforced as callee frees up storage. This should pass. + assert_ok!(builder::call(addr_caller) + .storage_deposit_limit(1) + .data((87u32, &addr_callee, U256::from(1u64)).encode()) + .build()); + }); +} - // Pass empty flags and therefore successfully instantiate the contract for later use. - let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) - .data(ReturnFlags::empty().bits().encode()) +#[test] +fn deposit_limit_in_nested_instantiate() { + let (wasm_caller, _code_hash_caller) = + compile_module("create_storage_and_instantiate").unwrap(); + let (wasm_callee, code_hash_callee) = compile_module("store_deploy").unwrap(); + const ED: u64 = 5; + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, 1_000_000); + // Create caller contract + let Contract { addr: addr_caller, account_id: caller_id } = + builder::bare_instantiate(Code::Upload(wasm_caller)) + .value(10_000u64) // this balance is later passed to the deployed contract .build_and_unwrap_contract(); + // Deploy a contract to get its occupied storage size + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm_callee)) + .data(vec![0, 0, 0, 0]) + .build_and_unwrap_contract(); + + let callee_info_len = ContractInfoOf::::get(&addr).unwrap().encoded_size() as u64; + + // We don't set a special deposit limit for the nested instantiation. + // + // The deposit limit set for the parent is insufficient for the instantiation, which + // requires: + // - callee_info_len + 2 for storing the new contract info, + // - ED for deployed contract account, + // - 2 for the storage item of 0 bytes being created in the callee constructor + // or (callee_info_len + 2 + ED + 2) Balance in total. + // + // Provided the limit is set to be 1 Balance less, + // this call should fail on the return from the caller contract. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(callee_info_len + 2 + ED + 1) + .data((0u32, &code_hash_callee, U256::from(0u64)).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); + // The charges made on instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Now we give enough limit for the instantiation itself, but require for 1 more storage + // byte in the constructor. Hence +1 Balance to the limit is needed. This should fail on + // the return from constructor. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(callee_info_len + 2 + ED + 2) + .data((1u32, &code_hash_callee, U256::from(0u64)).encode()) + .build(), + >::StorageDepositLimitExhausted, + ); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // 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, + ); + // The charges made on the instantiation should be rolled back. + assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + + // Same as above but requires for single added storage + // 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, + ); + // 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) + .data((1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 3 + 2)).encode()) + .build(); + + let returned = result.result.unwrap(); + // All balance of the caller except ED has been transferred to the callee. + // No deposit has been taken from it. + assert_eq!(::Currency::free_balance(&caller_id), ED); + // Get address of the deployed contract. + let addr_callee = H160::from_slice(&returned.data[0..20]); + let callee_account_id = ::AddressMapper::to_account_id(&addr_callee); + // 10_000 should be sent to callee from the caller contract, plus ED to be sent from the + // origin. + assert_eq!(::Currency::free_balance(&callee_account_id), 10_000 + ED); + // The origin should be charged with: + // - callee instantiation deposit = (callee_info_len + 2) + // - callee account ED + // - for writing an item of 1 byte to storage = 3 Balance + // - Immutable data storage item deposit + assert_eq!( + ::Currency::free_balance(&BOB), + 1_000_000 - (callee_info_len + 2 + ED + 3) + ); + // Check that deposit due to be charged still includes these 3 Balance + assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3)) + }); +} - // Calling extrinsic: revert leads to an error - assert_err_ignore_postinfo!( - builder::call(addr).data(input.clone()).build(), - >::ContractReverted, - ); - - // Calling directly: revert leads to success but the flags indicate the error - let result = builder::bare_call(addr).data(input).build_and_unwrap_result(); - assert_eq!(result.flags, flags); - assert_eq!(result.data, buffer); - }); - } - - #[test] - fn set_code_hash() { - let (wasm, code_hash) = compile_module("set_code_hash").unwrap(); - let (new_wasm, new_code_hash) = compile_module("new_set_code_hash_contract").unwrap(); - - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Instantiate the 'caller' - let Contract { addr: contract_addr, .. } = - builder::bare_instantiate(Code::Upload(wasm)) - .value(300_000) - .build_and_unwrap_contract(); - // upload new code - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - new_wasm.clone(), - deposit_limit::(), - )); - - System::reset_events(); - - // First call sets new code_hash and returns 1 - let result = builder::bare_call(contract_addr) - .data(new_code_hash.as_ref().to_vec()) - .debug(DebugInfo::UnsafeDebug) - .build_and_unwrap_result(); - assert_return_code!(result, 1); - - // Second calls new contract code that returns 2 - let result = builder::bare_call(contract_addr) - .debug(DebugInfo::UnsafeDebug) - .build_and_unwrap_result(); - assert_return_code!(result, 2); - - // Checking for the last event only - assert_eq!( - &System::events(), - &[ - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::ContractCodeUpdated { - contract: contract_addr, - new_code_hash, - old_code_hash: code_hash, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: contract_addr, - }), - topics: vec![], - }, - EventRecord { - phase: Phase::Initialization, - event: RuntimeEvent::Contracts(crate::Event::Called { - caller: Origin::from_account_id(ALICE), - contract: contract_addr, - }), - topics: vec![], - }, - ], - ); - }); - } - - #[test] - fn storage_deposit_limit_is_enforced() { - let (wasm, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let min_balance = Contracts::min_balance(); - - // Setting insufficient storage_deposit should fail. - assert_err!( - builder::bare_instantiate(Code::Upload(wasm.clone())) - // expected deposit is 2 * ed + 3 for the call - .storage_deposit_limit((2 * min_balance + 3 - 1).into()) - .build() - .result, - >::StorageDepositLimitExhausted, - ); - - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - - let info_deposit = test_utils::contract_info_storage_deposit(&addr); - // Check that the BOB contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + min_balance - ); - - // Create 1 byte of storage with a price of per byte, - // setting insufficient deposit limit, as it requires 3 Balance: - // 2 for the item added + 1 for the new storage item. - assert_err_ignore_postinfo!( - builder::call(addr) - .storage_deposit_limit(2) - .data(1u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - - // Create 1 byte of storage, should cost 3 Balance: - // 2 for the item added + 1 for the new storage item. - // Should pass as it fallbacks to DefaultDepositLimit. - assert_ok!(builder::call(addr) - .storage_deposit_limit(3) - .data(1u32.to_le_bytes().to_vec()) - .build()); - - // Use 4 more bytes of the storage for the same item, which requires 4 Balance. - // Should fail as DefaultDepositLimit is 3 and hence isn't enough. - assert_err_ignore_postinfo!( - builder::call(addr) - .storage_deposit_limit(3) - .data(5u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - }); - } - - #[test] - fn deposit_limit_in_nested_calls() { - let (wasm_caller, _code_hash_caller) = compile_module("create_storage_and_call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); +#[test] +fn deposit_limit_honors_liquidity_restrictions() { + let (wasm, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let bobs_balance = 1_000; + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, bobs_balance); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + + let info_deposit = test_utils::contract_info_storage_deposit(&addr); + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + min_balance + ); - // Create 100 bytes of storage with a price of per byte - // This is 100 Balance + 2 Balance for the item - assert_ok!(builder::call(addr_callee) - .storage_deposit_limit(102) + // check that the hold is honored + ::Currency::hold( + &HoldReason::CodeUploadDepositReserve.into(), + &BOB, + bobs_balance - min_balance, + ) + .unwrap(); + assert_err_ignore_postinfo!( + builder::call(addr) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(10_000) .data(100u32.to_le_bytes().to_vec()) - .build()); - - // We do not remove any storage but add a storage item of 12 bytes in the caller - // contract. This would cost 12 + 2 = 14 Balance. - // The nested call doesn't get a special limit, which is set by passing 0 to it. - // This should fail as the specified parent's limit is less than the cost: 13 < - // 14. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(13) - .data((100u32, &addr_callee, U256::from(0u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); - - // Now we specify the parent's limit high enough to cover the caller's storage - // additions. However, we use a single byte more in the callee, hence the storage - // deposit should be 15 Balance. - // The nested call doesn't get a special limit, which is set by passing 0 to it. - // This should fail as the specified parent's limit is less than the cost: 14 - // < 15. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(14) - .data((101u32, &addr_callee, U256::from(0u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); + .build(), + >::StorageDepositLimitExhausted, + ); + assert_eq!(::Currency::free_balance(&BOB), min_balance); + }); +} - // Now we specify the parent's limit high enough to cover both the caller's and callee's - // storage additions. However, we set a special deposit limit of 1 Balance for the - // 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, - ); +#[test] +fn deposit_limit_honors_existential_deposit() { + let (wasm, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, 300); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + + let info_deposit = test_utils::contract_info_storage_deposit(&addr); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + min_balance + info_deposit + ); - // 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 - // making the test case fail. We don't set a special limit for the nested call here. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .storage_deposit_limit(0) - .data((87u32, &addr_callee, U256::from(0u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); + // check that the deposit can't bring the account below the existential deposit + assert_err_ignore_postinfo!( + builder::call(addr) + .origin(RuntimeOrigin::signed(BOB)) + .storage_deposit_limit(10_000) + .data(100u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositLimitExhausted, + ); + assert_eq!(::Currency::free_balance(&BOB), 300); + }); +} - let _ = ::Currency::set_balance(&ALICE, 511); +#[test] +fn deposit_limit_honors_min_leftover() { + let (wasm, _code_hash) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let _ = ::Currency::set_balance(&BOB, 1_000); + let min_balance = Contracts::min_balance(); + + // Instantiate the BOB contract. + let Contract { addr, account_id } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + + let info_deposit = test_utils::contract_info_storage_deposit(&addr); + + // Check that the contract has been instantiated and has the minimum balance and the + // storage deposit + assert_eq!(get_contract(&addr).total_deposit(), info_deposit); + assert_eq!( + ::Currency::total_balance(&account_id), + info_deposit + min_balance + ); - // 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, - ); + // check that the minimum leftover (value send) is considered + // given the minimum deposit of 200 sending 750 will only leave + // 50 for the storage deposit. Which is not enough to store the 50 bytes + // as we also need 2 bytes for the item + assert_err_ignore_postinfo!( + builder::call(addr) + .origin(RuntimeOrigin::signed(BOB)) + .value(750) + .storage_deposit_limit(10_000) + .data(50u32.to_le_bytes().to_vec()) + .build(), + >::StorageDepositLimitExhausted, + ); + assert_eq!(::Currency::free_balance(&BOB), 1_000); + }); +} - // 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 - // enforced as callee frees up storage. This should pass. - assert_ok!(builder::call(addr_caller) - .storage_deposit_limit(1) - .data((87u32, &addr_callee, U256::from(1u64)).encode()) - .build()); - }); - } +#[test] +fn locking_delegate_dependency_works() { + // set hash lock up deposit to 30%, to test deposit calculation. + CODE_HASH_LOCKUP_DEPOSIT_PERCENT.with(|c| *c.borrow_mut() = Perbill::from_percent(30)); + + let (wasm_caller, self_code_hash) = compile_module("locking_delegate_dependency").unwrap(); + let callee_codes: Vec<_> = + (0..limits::DELEGATE_DEPENDENCIES + 1).map(|idx| dummy_unique(idx)).collect(); + let callee_hashes: Vec<_> = callee_codes + .iter() + .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 + }; - #[test] - fn deposit_limit_in_nested_instantiate() { - let (wasm_caller, _code_hash_caller) = - compile_module("create_storage_and_instantiate").unwrap(); - let (wasm_callee, code_hash_callee) = compile_module("store_deploy").unwrap(); - const ED: u64 = 5; - ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, 1_000_000); - // Create caller contract - let Contract { addr: addr_caller, account_id: caller_id } = - builder::bare_instantiate(Code::Upload(wasm_caller)) - .value(10_000u64) // this balance is later passed to the deployed contract - .build_and_unwrap_contract(); - // Deploy a contract to get its occupied storage size - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm_callee)) - .data(vec![0, 0, 0, 0]) - .build_and_unwrap_contract(); + // Define inputs with various actions to test locking / unlocking delegate_dependencies. + // See the contract for more details. + let noop_input = (0u32, callee_hashes[0]); + let lock_delegate_dependency_input = (1u32, callee_hashes[0]); + let unlock_delegate_dependency_input = (2u32, callee_hashes[0]); + let terminate_input = (3u32, callee_hashes[0]); + + // 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((action, hash2addr(code_hash), code_hash).encode()) + .build() + }; - let callee_info_len = ContractInfoOf::::get(&addr).unwrap().encoded_size() as u64; - - // We don't set a special deposit limit for the nested instantiation. - // - // The deposit limit set for the parent is insufficient for the instantiation, which - // requires: - // - callee_info_len + 2 for storing the new contract info, - // - ED for deployed contract account, - // - 2 for the storage item of 0 bytes being created in the callee constructor - // or (callee_info_len + 2 + ED + 2) Balance in total. - // - // Provided the limit is set to be 1 Balance less, - // this call should fail on the return from the caller contract. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(callee_info_len + 2 + ED + 1) - .data((0u32, &code_hash_callee, U256::from(0u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); - // The charges made on instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // Now we give enough limit for the instantiation itself, but require for 1 more storage - // byte in the constructor. Hence +1 Balance to the limit is needed. This should fail on - // the return from constructor. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(callee_info_len + 2 + ED + 2) - .data((1u32, &code_hash_callee, U256::from(0u64)).encode()) - .build(), - >::StorageDepositLimitExhausted, - ); - // The charges made on the instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // 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, - ); - // The charges made on the instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); - - // Same as above but requires for single added storage - // 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, - ); - // The charges made on the instantiation should be rolled back. - assert_eq!(::Currency::free_balance(&BOB), 1_000_000); + // 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((action, hash2addr(code_hash), code_hash).encode()) + .build() + }; + const ED: u64 = 2000; + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + let _ = Balances::set_balance(&ALICE_FALLBACK, 1_000_000); + + // Instantiate with lock_delegate_dependency should fail since the code is not yet on + // chain. + assert_err!( + instantiate(&lock_delegate_dependency_input).result, + Error::::CodeNotFound + ); - // 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) - .data( - (1u32, &code_hash_callee, U256::from(callee_info_len + 2 + ED + 3 + 2)) - .encode(), + // 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, code_hash } = + Contracts::bare_upload_code( + RuntimeOrigin::signed(ALICE_FALLBACK), + code.clone(), + deposit_limit::(), ) - .build(); - - let returned = result.result.unwrap(); - // All balance of the caller except ED has been transferred to the callee. - // No deposit has been taken from it. - assert_eq!(::Currency::free_balance(&caller_id), ED); - // Get address of the deployed contract. - let addr_callee = H160::from_slice(&returned.data[0..20]); - let callee_account_id = ::AddressMapper::to_account_id(&addr_callee); - // 10_000 should be sent to callee from the caller contract, plus ED to be sent from the - // origin. - assert_eq!(::Currency::free_balance(&callee_account_id), 10_000 + ED); - // The origin should be charged with: - // - callee instantiation deposit = (callee_info_len + 2) - // - callee account ED - // - for writing an item of 1 byte to storage = 3 Balance - // - Immutable data storage item deposit - assert_eq!( - ::Currency::free_balance(&BOB), - 1_000_000 - (callee_info_len + 2 + ED + 3) - ); - // Check that deposit due to be charged still includes these 3 Balance - assert_eq!(result.storage_deposit.charge_or_zero(), (callee_info_len + 2 + ED + 3)) - }); - } + .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()); + } - #[test] - fn deposit_limit_honors_liquidity_restrictions() { - let (wasm, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let bobs_balance = 1_000; - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, bobs_balance); - let min_balance = Contracts::min_balance(); + // Instantiate should now work. + let addr_caller = instantiate(&lock_delegate_dependency_input).result.unwrap().addr; + let caller_account_id = ::AddressMapper::to_account_id(&addr_caller); - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + // There should be a dependency and a deposit. + let contract = test_utils::get_contract(&addr_caller); - let info_deposit = test_utils::contract_info_storage_deposit(&addr); - // Check that the contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + min_balance - ); + let dependency_deposit = &CodeHashLockupDepositPercent::get().mul_ceil(deposit); + assert_eq!( + contract.delegate_dependencies().get(&callee_hashes[0]), + Some(dependency_deposit) + ); + assert_eq!( + test_utils::get_balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &caller_account_id + ), + dependency_deposit + contract.storage_base_deposit() + ); - // check that the hold is honored - ::Currency::hold( - &HoldReason::CodeUploadDepositReserve.into(), - &BOB, - bobs_balance - min_balance, - ) - .unwrap(); - assert_err_ignore_postinfo!( - builder::call(addr) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(10_000) - .data(100u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - assert_eq!(::Currency::free_balance(&BOB), min_balance); - }); - } + // Removing the code should fail, since we have added a dependency. + assert_err!( + Contracts::remove_code(RuntimeOrigin::signed(ALICE_FALLBACK), callee_hashes[0]), + >::CodeInUse + ); - #[test] - fn deposit_limit_honors_existential_deposit() { - let (wasm, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, 300); - let min_balance = Contracts::min_balance(); + // Locking an already existing dependency should fail. + assert_err!( + call(&addr_caller, &lock_delegate_dependency_input).result, + Error::::DelegateDependencyAlreadyExists + ); - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + // Locking self should fail. + assert_err!( + builder::bare_call(addr_caller) + .origin(RuntimeOrigin::signed(ALICE_FALLBACK)) + .data((1u32, &addr_caller, self_code_hash).encode()) + .build() + .result, + Error::::CannotAddSelfAsDelegateDependency + ); - let info_deposit = test_utils::contract_info_storage_deposit(&addr); + // Locking more than the maximum allowed delegate_dependencies should fail. + for hash in &callee_hashes[1..callee_hashes.len() - 1] { + call(&addr_caller, &(1u32, *hash)).result.unwrap(); + } + assert_err!( + call(&addr_caller, &(1u32, *callee_hashes.last().unwrap())).result, + Error::::MaxDelegateDependenciesReached + ); - // Check that the contract has been instantiated and has the minimum balance - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - min_balance + info_deposit - ); + // Unlocking all dependency should work. + for hash in &callee_hashes[..callee_hashes.len() - 1] { + call(&addr_caller, &(2u32, *hash)).result.unwrap(); + } - // check that the deposit can't bring the account below the existential deposit - assert_err_ignore_postinfo!( - builder::call(addr) - .origin(RuntimeOrigin::signed(BOB)) - .storage_deposit_limit(10_000) - .data(100u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - assert_eq!(::Currency::free_balance(&BOB), 300); - }); - } + // Dependency should be removed, and deposit should be returned. + let contract = test_utils::get_contract(&addr_caller); + assert!(contract.delegate_dependencies().is_empty()); + assert_eq!( + test_utils::get_balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &caller_account_id + ), + contract.storage_base_deposit() + ); - #[test] - fn deposit_limit_honors_min_leftover() { - let (wasm, _code_hash) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let _ = ::Currency::set_balance(&BOB, 1_000); - let min_balance = Contracts::min_balance(); + // Removing a nonexistent dependency should fail. + assert_err!( + call(&addr_caller, &unlock_delegate_dependency_input).result, + Error::::DelegateDependencyNotFound + ); - // Instantiate the BOB contract. - let Contract { addr, account_id } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); + // 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((1u32, hash2addr(&callee_hashes[0]), callee_hashes[0]).encode()) + .build() + .result, + Error::::StorageDepositLimitExhausted + ); - let info_deposit = test_utils::contract_info_storage_deposit(&addr); + // Since we unlocked the dependency we should now be able to remove the code. + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE_FALLBACK), callee_hashes[0])); - // Check that the contract has been instantiated and has the minimum balance and the - // storage deposit - assert_eq!(get_contract(&addr).total_deposit(), info_deposit); - assert_eq!( - ::Currency::total_balance(&account_id), - info_deposit + min_balance - ); + // Calling should fail since the delegated contract is not on chain anymore. + assert_err!(call(&addr_caller, &noop_input).result, Error::::ContractTrapped); - // check that the minimum leftover (value send) is considered - // given the minimum deposit of 200 sending 750 will only leave - // 50 for the storage deposit. Which is not enough to store the 50 bytes - // as we also need 2 bytes for the item - assert_err_ignore_postinfo!( - builder::call(addr) - .origin(RuntimeOrigin::signed(BOB)) - .value(750) - .storage_deposit_limit(10_000) - .data(50u32.to_le_bytes().to_vec()) - .build(), - >::StorageDepositLimitExhausted, - ); - assert_eq!(::Currency::free_balance(&BOB), 1_000); - }); - } + // Add the dependency back. + Contracts::upload_code( + RuntimeOrigin::signed(ALICE_FALLBACK), + callee_codes[0].clone(), + deposit_limit::(), + ) + .unwrap(); + call(&addr_caller, &lock_delegate_dependency_input).result.unwrap(); + + // Call terminate should work, and return the deposit. + let balance_before = test_utils::get_balance(&ALICE_FALLBACK); + assert_ok!(call(&addr_caller, &terminate_input).result); + assert_eq!( + test_utils::get_balance(&ALICE_FALLBACK), + ED + balance_before + contract.storage_base_deposit() + dependency_deposit + ); - #[test] - fn locking_delegate_dependency_works() { - // set hash lock up deposit to 30%, to test deposit calculation. - CODE_HASH_LOCKUP_DEPOSIT_PERCENT.with(|c| *c.borrow_mut() = Perbill::from_percent(30)); + // Terminate should also remove the dependency, so we can remove the code. + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE_FALLBACK), callee_hashes[0])); + }); +} - let (wasm_caller, self_code_hash) = compile_module("locking_delegate_dependency").unwrap(); - let callee_codes: Vec<_> = - (0..limits::DELEGATE_DEPENDENCIES + 1).map(|idx| dummy_unique(idx)).collect(); - let callee_hashes: Vec<_> = callee_codes - .iter() - .map(|c| sp_core::H256(sp_io::hashing::keccak_256(c))) - .collect(); +#[test] +fn native_dependency_deposit_works() { + let (wasm, code_hash) = compile_module("set_code_hash").unwrap(); + let (dummy_wasm, dummy_code_hash) = compile_module("dummy").unwrap(); - // Define inputs with various actions to test locking / unlocking delegate_dependencies. - // See the contract for more details. - let noop_input = (0u32, callee_hashes[0]); - let lock_delegate_dependency_input = (1u32, callee_hashes[0]); - let unlock_delegate_dependency_input = (2u32, callee_hashes[0]); - let terminate_input = (3u32, callee_hashes[0]); - - // Instantiate the caller contract with the given input. - let instantiate = |input: &(u32, H256)| { - builder::bare_instantiate(Code::Upload(wasm_caller.clone())) - .origin(RuntimeOrigin::signed(ETH_ALICE)) - .data(input.encode()) - .build() - }; + // Set hash lock up deposit to 30%, to test deposit calculation. + CODE_HASH_LOCKUP_DEPOSIT_PERCENT.with(|c| *c.borrow_mut() = Perbill::from_percent(30)); - // Call contract with the given input. - let call = |addr_caller: &H160, input: &(u32, H256)| { - builder::bare_call(*addr_caller) - .origin(RuntimeOrigin::signed(ETH_ALICE)) - .data(input.encode()) - .build() - }; - const ED: u64 = 2000; - ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { - let _ = Balances::set_balance(Ð_ALICE, 1_000_000); + // Test with both existing and uploaded code + for code in [Code::Upload(wasm.clone()), Code::Existing(code_hash)] { + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let lockup_deposit_percent = CodeHashLockupDepositPercent::get(); - // Instantiate with lock_delegate_dependency should fail since the code is not yet on - // chain. - assert_err!( - instantiate(&lock_delegate_dependency_input).result, - Error::::CodeNotFound - ); + // Upload the dummy contract, + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + dummy_wasm.clone(), + deposit_limit::(), + ) + .unwrap(); - // 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, .. } = - Contracts::bare_upload_code( - RuntimeOrigin::signed(ETH_ALICE), - code.clone(), + // Upload `set_code_hash` contracts if using Code::Existing. + let add_upload_deposit = match code { + Code::Existing(_) => { + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), deposit_limit::(), ) .unwrap(); - deposit = deposit_per_code; - } - - // Instantiate should now work. - let addr_caller = instantiate(&lock_delegate_dependency_input).result.unwrap().addr; - let caller_account_id = ::AddressMapper::to_account_id(&addr_caller); - - // There should be a dependency and a deposit. - let contract = test_utils::get_contract(&addr_caller); + false + }, + Code::Upload(_) => true, + }; - let dependency_deposit = &CodeHashLockupDepositPercent::get().mul_ceil(deposit); - assert_eq!( - contract.delegate_dependencies().get(&callee_hashes[0]), - Some(dependency_deposit) - ); - assert_eq!( - test_utils::get_balance_on_hold( - &HoldReason::StorageDepositReserve.into(), - &caller_account_id - ), - dependency_deposit + contract.storage_base_deposit() - ); + // Instantiate the set_code_hash contract. + let res = builder::bare_instantiate(code).build(); - // Removing the code should fail, since we have added a dependency. - assert_err!( - Contracts::remove_code(RuntimeOrigin::signed(ETH_ALICE), callee_hashes[0]), - >::CodeInUse - ); + let addr = res.result.unwrap().addr; + let account_id = ::AddressMapper::to_account_id(&addr); + let base_deposit = test_utils::contract_info_storage_deposit(&addr); + let upload_deposit = test_utils::get_code_deposit(&code_hash); + let extra_deposit = add_upload_deposit.then(|| upload_deposit).unwrap_or_default(); - // Locking an already existing dependency should fail. - assert_err!( - call(&addr_caller, &lock_delegate_dependency_input).result, - Error::::DelegateDependencyAlreadyExists - ); + // Check initial storage_deposit + // The base deposit should be: contract_info_storage_deposit + 30% * deposit + let deposit = + extra_deposit + base_deposit + lockup_deposit_percent.mul_ceil(upload_deposit); - // Locking self should fail. - assert_err!( - call(&addr_caller, &(1u32, self_code_hash)).result, - Error::::CannotAddSelfAsDelegateDependency - ); + assert_eq!(res.storage_deposit.charge_or_zero(), deposit + Contracts::min_balance()); - // Locking more than the maximum allowed delegate_dependencies should fail. - for hash in &callee_hashes[1..callee_hashes.len() - 1] { - call(&addr_caller, &(1u32, *hash)).result.unwrap(); - } - assert_err!( - call(&addr_caller, &(1u32, *callee_hashes.last().unwrap())).result, - Error::::MaxDelegateDependenciesReached - ); + // call set_code_hash + builder::bare_call(addr) + .data(dummy_code_hash.encode()) + .build_and_unwrap_result(); - // Unlocking all dependency should work. - for hash in &callee_hashes[..callee_hashes.len() - 1] { - call(&addr_caller, &(2u32, *hash)).result.unwrap(); - } + // Check updated storage_deposit + let code_deposit = test_utils::get_code_deposit(&dummy_code_hash); + let deposit = base_deposit + lockup_deposit_percent.mul_ceil(code_deposit); + assert_eq!(test_utils::get_contract(&addr).storage_base_deposit(), deposit); - // Dependency should be removed, and deposit should be returned. - let contract = test_utils::get_contract(&addr_caller); - assert!(contract.delegate_dependencies().is_empty()); assert_eq!( test_utils::get_balance_on_hold( &HoldReason::StorageDepositReserve.into(), - &caller_account_id + &account_id ), - contract.storage_base_deposit() + deposit ); + }); + } +} - // Removing a nonexistent dependency should fail. - assert_err!( - call(&addr_caller, &unlock_delegate_dependency_input).result, - Error::::DelegateDependencyNotFound - ); +#[test] +fn block_hash_works() { + let (code, _) = compile_module("block_hash").unwrap(); - // 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()) - .build() - .result, - Error::::StorageDepositLimitExhausted - ); + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Since we unlocked the dependency we should now be able to remove the code. - assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ETH_ALICE), callee_hashes[0])); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - // Calling should fail since the delegated contract is not on chain anymore. - assert_err!(call(&addr_caller, &noop_input).result, Error::::ContractTrapped); + // The genesis config sets to the block number to 1 + let block_hash = [1; 32]; + frame_system::BlockHash::::insert( + &crate::BlockNumberFor::::from(0u32), + ::Hash::from(&block_hash), + ); + assert_ok!(builder::call(addr) + .data((U256::zero(), H256::from(block_hash)).encode()) + .build()); - // Add the dependency back. - Contracts::upload_code( - RuntimeOrigin::signed(ETH_ALICE), - callee_codes[0].clone(), - deposit_limit::(), - ) - .unwrap(); - call(&addr_caller, &lock_delegate_dependency_input).result.unwrap(); + // A block number out of range returns the zero value + assert_ok!(builder::call(addr).data((U256::from(1), H256::zero()).encode()).build()); + }); +} - // Call terminate should work, and return the deposit. - let balance_before = test_utils::get_balance(Ð_ALICE); - assert_ok!(call(&addr_caller, &terminate_input).result); - assert_eq!( - test_utils::get_balance(Ð_ALICE), - ED + balance_before + contract.storage_base_deposit() + dependency_deposit - ); +#[test] +fn root_cannot_upload_code() { + let (wasm, _) = compile_module("dummy").unwrap(); - // Terminate should also remove the dependency, so we can remove the code. - assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ETH_ALICE), callee_hashes[0])); - }); - } + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Contracts::upload_code(RuntimeOrigin::root(), wasm, deposit_limit::()), + DispatchError::BadOrigin, + ); + }); +} - #[test] - fn native_dependency_deposit_works() { - let (wasm, code_hash) = compile_module("set_code_hash").unwrap(); - let (dummy_wasm, dummy_code_hash) = compile_module("dummy").unwrap(); +#[test] +fn root_cannot_remove_code() { + let (_, code_hash) = compile_module("dummy").unwrap(); - // Set hash lock up deposit to 30%, to test deposit calculation. - CODE_HASH_LOCKUP_DEPOSIT_PERCENT.with(|c| *c.borrow_mut() = Perbill::from_percent(30)); + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Contracts::remove_code(RuntimeOrigin::root(), code_hash), + DispatchError::BadOrigin, + ); + }); +} - // Test with both existing and uploaded code - for code in [Code::Upload(wasm.clone()), Code::Existing(code_hash)] { - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let lockup_deposit_percent = CodeHashLockupDepositPercent::get(); +#[test] +fn signed_cannot_set_code() { + let (_, code_hash) = compile_module("dummy").unwrap(); - // Upload the dummy contract, - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - dummy_wasm.clone(), - deposit_limit::(), - ) - .unwrap(); + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Contracts::set_code(RuntimeOrigin::signed(ALICE), BOB_ADDR, code_hash), + DispatchError::BadOrigin, + ); + }); +} - // Upload `set_code_hash` contracts if using Code::Existing. - let add_upload_deposit = match code { - Code::Existing(_) => { - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - wasm.clone(), - deposit_limit::(), - ) - .unwrap(); - false - }, - Code::Upload(_) => true, - }; +#[test] +fn none_cannot_call_code() { + ExtBuilder::default().build().execute_with(|| { + assert_err_ignore_postinfo!( + builder::call(BOB_ADDR).origin(RuntimeOrigin::none()).build(), + DispatchError::BadOrigin, + ); + }); +} - // Instantiate the set_code_hash contract. - let res = builder::bare_instantiate(code).build(); +#[test] +fn root_can_call() { + let (wasm, _) = compile_module("dummy").unwrap(); - let addr = res.result.unwrap().addr; - let account_id = ::AddressMapper::to_account_id(&addr); - let base_deposit = test_utils::contract_info_storage_deposit(&addr); - let upload_deposit = test_utils::get_code_deposit(&code_hash); - let extra_deposit = add_upload_deposit.then(|| upload_deposit).unwrap_or_default(); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Check initial storage_deposit - // The base deposit should be: contract_info_storage_deposit + 30% * deposit - let deposit = - extra_deposit + base_deposit + lockup_deposit_percent.mul_ceil(upload_deposit); + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); - assert_eq!( - res.storage_deposit.charge_or_zero(), - deposit + Contracts::min_balance() - ); + // Call the contract. + assert_ok!(builder::call(addr).origin(RuntimeOrigin::root()).build()); + }); +} - // call set_code_hash - builder::bare_call(addr) - .data(dummy_code_hash.encode()) - .build_and_unwrap_result(); +#[test] +fn root_cannot_instantiate_with_code() { + let (wasm, _) = compile_module("dummy").unwrap(); - // Check updated storage_deposit - let code_deposit = test_utils::get_code_deposit(&dummy_code_hash); - let deposit = base_deposit + lockup_deposit_percent.mul_ceil(code_deposit); - assert_eq!(test_utils::get_contract(&addr).storage_base_deposit(), deposit); + ExtBuilder::default().build().execute_with(|| { + assert_err_ignore_postinfo!( + builder::instantiate_with_code(wasm).origin(RuntimeOrigin::root()).build(), + DispatchError::BadOrigin + ); + }); +} - assert_eq!( - test_utils::get_balance_on_hold( - &HoldReason::StorageDepositReserve.into(), - &account_id - ), - deposit - ); - }); - } - } +#[test] +fn root_cannot_instantiate() { + let (_, code_hash) = compile_module("dummy").unwrap(); - #[test] - fn root_cannot_upload_code() { - let (wasm, _) = compile_module("dummy").unwrap(); + ExtBuilder::default().build().execute_with(|| { + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).origin(RuntimeOrigin::root()).build(), + DispatchError::BadOrigin + ); + }); +} - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - Contracts::upload_code(RuntimeOrigin::root(), wasm, deposit_limit::()), - DispatchError::BadOrigin, - ); - }); - } +#[test] +fn only_upload_origin_can_upload() { + let (wasm, _) = compile_module("dummy").unwrap(); + UploadAccount::set(Some(ALICE)); + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let _ = Balances::set_balance(&BOB, 1_000_000); + + assert_err!( + Contracts::upload_code(RuntimeOrigin::root(), wasm.clone(), deposit_limit::(),), + DispatchError::BadOrigin + ); - #[test] - fn root_cannot_remove_code() { - let (_, code_hash) = compile_module("dummy").unwrap(); + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(BOB), + wasm.clone(), + deposit_limit::(), + ), + DispatchError::BadOrigin + ); - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - Contracts::remove_code(RuntimeOrigin::root(), code_hash), - DispatchError::BadOrigin, - ); - }); - } + // Only alice is allowed to upload contract code. + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + deposit_limit::(), + )); + }); +} - #[test] - fn signed_cannot_set_code() { - let (_, code_hash) = compile_module("dummy").unwrap(); +#[test] +fn only_instantiation_origin_can_instantiate() { + let (code, code_hash) = compile_module("dummy").unwrap(); + InstantiateAccount::set(Some(ALICE)); + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let _ = Balances::set_balance(&BOB, 1_000_000); + + assert_err_ignore_postinfo!( + builder::instantiate_with_code(code.clone()) + .origin(RuntimeOrigin::root()) + .build(), + DispatchError::BadOrigin + ); - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - Contracts::set_code(RuntimeOrigin::signed(ALICE), BOB_ADDR, code_hash), - DispatchError::BadOrigin, - ); - }); - } + assert_err_ignore_postinfo!( + builder::instantiate_with_code(code.clone()) + .origin(RuntimeOrigin::signed(BOB)) + .build(), + DispatchError::BadOrigin + ); - #[test] - fn none_cannot_call_code() { - ExtBuilder::default().build().execute_with(|| { - assert_err_ignore_postinfo!( - builder::call(BOB_ADDR).origin(RuntimeOrigin::none()).build(), - DispatchError::BadOrigin, - ); - }); - } + // Only Alice can instantiate + assert_ok!(builder::instantiate_with_code(code).build()); - #[test] - fn root_can_call() { - let (wasm, _) = compile_module("dummy").unwrap(); + // Bob cannot instantiate with either `instantiate_with_code` or `instantiate`. + assert_err_ignore_postinfo!( + builder::instantiate(code_hash).origin(RuntimeOrigin::signed(BOB)).build(), + DispatchError::BadOrigin + ); + }); +} - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); +#[test] +fn balance_of_api() { + let (wasm, _code_hash) = compile_module("balance_of").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + let _ = Balances::set_balance(&ALICE_FALLBACK, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(wasm.to_vec())).build_and_unwrap_contract(); + + // The fixture asserts a non-zero returned free balance of the account; + // The ALICE_FALLBACK account is endowed; + // Hence we should not revert + assert_ok!(builder::call(addr).data(ALICE_ADDR.0.to_vec()).build()); + + // The fixture asserts a non-zero returned free balance of the account; + // The ETH_BOB account is not endowed; + // Hence we should revert + assert_err_ignore_postinfo!( + builder::call(addr).data(BOB_ADDR.0.to_vec()).build(), + >::ContractTrapped + ); + }); +} - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(wasm)).build_and_unwrap_contract(); +#[test] +fn balance_api_returns_free_balance() { + let (wasm, _code_hash) = compile_module("balance").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Instantiate the BOB contract without any extra balance. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(wasm.to_vec())).build_and_unwrap_contract(); + + let value = 0; + // Call BOB which makes it call the balance runtime API. + // The contract code asserts that the returned balance is 0. + assert_ok!(builder::call(addr).value(value).build()); + + let value = 1; + // Calling with value will trap the contract. + assert_err_ignore_postinfo!( + builder::call(addr).value(value).build(), + >::ContractTrapped + ); + }); +} - // Call the contract. - assert_ok!(builder::call(addr).origin(RuntimeOrigin::root()).build()); - }); - } +#[test] +fn gas_consumed_is_linear_for_nested_calls() { + let (code, _code_hash) = compile_module("recurse").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + let [gas_0, gas_1, gas_2, gas_max] = { + [0u32, 1u32, 2u32, limits::CALL_STACK_DEPTH] + .iter() + .map(|i| { + let result = builder::bare_call(addr).data(i.encode()).build(); + assert_ok!(result.result); + result.gas_consumed + }) + .collect::>() + .try_into() + .unwrap() + }; - #[test] - fn root_cannot_instantiate_with_code() { - let (wasm, _) = compile_module("dummy").unwrap(); + let gas_per_recursion = gas_2.checked_sub(&gas_1).unwrap(); + assert_eq!(gas_max, gas_0 + gas_per_recursion * limits::CALL_STACK_DEPTH as u64); + }); +} - ExtBuilder::default().build().execute_with(|| { - assert_err_ignore_postinfo!( - builder::instantiate_with_code(wasm).origin(RuntimeOrigin::root()).build(), - DispatchError::BadOrigin - ); - }); - } +#[test] +fn read_only_call_cannot_store() { + let (wasm_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + // Read-only call fails when modifying storage. + assert_err_ignore_postinfo!( + builder::call(addr_caller).data((&addr_callee, 100u32).encode()).build(), + >::ContractTrapped + ); + }); +} - #[test] - fn root_cannot_instantiate() { - let (_, code_hash) = compile_module("dummy").unwrap(); +#[test] +fn read_only_call_cannot_transfer() { + let (wasm_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + // Read-only call fails when a non-zero value is set. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data( + (addr_callee, pallet_revive_uapi::CallFlags::READ_ONLY.bits(), 100u64).encode() + ) + .build(), + >::StateChangeDenied + ); + }); +} - ExtBuilder::default().build().execute_with(|| { - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).origin(RuntimeOrigin::root()).build(), - DispatchError::BadOrigin - ); - }); - } +#[test] +fn read_only_subsequent_call_cannot_store() { + let (wasm_read_only_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); + let (wasm_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_read_only_caller)) + .build_and_unwrap_contract(); + let Contract { addr: addr_subsequent_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + // Subsequent call input. + let input = (&addr_callee, pallet_revive_uapi::CallFlags::empty().bits(), 0u64, 100u32); + + // Read-only call fails when modifying storage. + assert_err_ignore_postinfo!( + builder::call(addr_caller) + .data((&addr_subsequent_caller, input).encode()) + .build(), + >::ContractTrapped + ); + }); +} - #[test] - fn only_upload_origin_can_upload() { - let (wasm, _) = compile_module("dummy").unwrap(); - UploadAccount::set(Some(ALICE)); - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let _ = Balances::set_balance(&BOB, 1_000_000); +#[test] +fn read_only_call_works() { + let (wasm_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); + let (wasm_callee, _code_hash_callee) = compile_module("dummy").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + let Contract { addr: addr_caller, .. } = + builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); + let Contract { addr: addr_callee, .. } = + builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + + assert_ok!(builder::call(addr_caller).data(addr_callee.encode()).build()); + }); +} - assert_err!( - Contracts::upload_code( - RuntimeOrigin::root(), - wasm.clone(), - deposit_limit::(), - ), - DispatchError::BadOrigin - ); +#[test] +fn create1_with_value_works() { + let (code, code_hash) = compile_module("create1_with_value").unwrap(); + let value = 42; + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: Deploys itself using create1 and the expected value + assert_ok!(builder::call(addr).value(value).data(code_hash.encode()).build()); + + // We should see the expected balance at the expected account + let address = crate::address::create1(&addr, 0); + let account_id = ::AddressMapper::to_account_id(&address); + let usable_balance = ::Currency::usable_balance(&account_id); + assert_eq!(usable_balance, value); + }); +} - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(BOB), - wasm.clone(), - deposit_limit::(), - ), - DispatchError::BadOrigin - ); +#[test] +fn static_data_limit_is_enforced() { + let (oom_rw_trailing, _) = compile_module("oom_rw_trailing").unwrap(); + let (oom_rw_included, _) = compile_module("oom_rw_included").unwrap(); + let (oom_ro, _) = compile_module("oom_ro").unwrap(); - // Only alice is allowed to upload contract code. - assert_ok!(Contracts::upload_code( + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); + + assert_err!( + Contracts::upload_code( RuntimeOrigin::signed(ALICE), - wasm.clone(), + oom_rw_trailing, deposit_limit::(), - )); - }); - } - - #[test] - fn only_instantiation_origin_can_instantiate() { - let (code, code_hash) = compile_module("dummy").unwrap(); - InstantiateAccount::set(Some(ALICE)); - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let _ = Balances::set_balance(&BOB, 1_000_000); - - assert_err_ignore_postinfo!( - builder::instantiate_with_code(code.clone()) - .origin(RuntimeOrigin::root()) - .build(), - DispatchError::BadOrigin - ); + ), + >::StaticMemoryTooLarge + ); - assert_err_ignore_postinfo!( - builder::instantiate_with_code(code.clone()) - .origin(RuntimeOrigin::signed(BOB)) - .build(), - DispatchError::BadOrigin - ); + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + oom_rw_included, + deposit_limit::(), + ), + >::BlobTooLarge + ); - // Only Alice can instantiate - assert_ok!(builder::instantiate_with_code(code).build()); + assert_err!( + Contracts::upload_code(RuntimeOrigin::signed(ALICE), oom_ro, deposit_limit::(),), + >::BlobTooLarge + ); + }); +} - // Bob cannot instantiate with either `instantiate_with_code` or `instantiate`. - assert_err_ignore_postinfo!( - builder::instantiate(code_hash).origin(RuntimeOrigin::signed(BOB)).build(), - DispatchError::BadOrigin - ); - }); - } +#[test] +fn call_diverging_out_len_works() { + let (code, _) = compile_module("call_diverging_out_len").unwrap(); - #[test] - fn balance_of_api() { - let (wasm, _code_hash) = compile_module("balance_of").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); - let _ = Balances::set_balance(Ð_ALICE, 1_000_000); - - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(wasm.to_vec())).build_and_unwrap_contract(); - - // The fixture asserts a non-zero returned free balance of the account; - // The ETH_ALICE account is endowed; - // Hence we should not revert - assert_ok!(builder::call(addr).data(ALICE_ADDR.0.to_vec()).build()); - - // The fixture asserts a non-zero returned free balance of the account; - // The ETH_BOB account is not endowed; - // Hence we should revert - assert_err_ignore_postinfo!( - builder::call(addr).data(BOB_ADDR.0.to_vec()).build(), - >::ContractTrapped - ); - }); - } + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - #[test] - fn balance_api_returns_free_balance() { - let (wasm, _code_hash) = compile_module("balance").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Create the contract: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - // Instantiate the BOB contract without any extra balance. - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(wasm.to_vec())).build_and_unwrap_contract(); + // Call the contract: It will issue calls and deploys, asserting on + // correct output if the supplied output length was smaller than + // than what the callee returned. + assert_ok!(builder::call(addr).build()); + }); +} - let value = 0; - // Call BOB which makes it call the balance runtime API. - // The contract code asserts that the returned balance is 0. - assert_ok!(builder::call(addr).value(value).build()); +#[test] +fn chain_id_works() { + let (code, _) = compile_module("chain_id").unwrap(); - let value = 1; - // Calling with value will trap the contract. - assert_err_ignore_postinfo!( - builder::call(addr).value(value).build(), - >::ContractTrapped - ); - }); - } + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - #[test] - fn gas_consumed_is_linear_for_nested_calls() { - let (code, _code_hash) = compile_module("recurse").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let chain_id = U256::from(::ChainId::get()); + let received = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_result(); + assert_eq!(received.result.data, chain_id.encode()); + }); +} - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); +#[test] +fn return_data_api_works() { + let (code_return_data_api, _) = compile_module("return_data_api").unwrap(); + let (code_return_with_data, hash_return_with_data) = + compile_module("return_with_data").unwrap(); - let [gas_0, gas_1, gas_2, gas_max] = { - [0u32, 1u32, 2u32, limits::CALL_STACK_DEPTH] - .iter() - .map(|i| { - let result = builder::bare_call(addr).data(i.encode()).build(); - assert_ok!(result.result); - result.gas_consumed - }) - .collect::>() - .try_into() - .unwrap() - }; + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - let gas_per_recursion = gas_2.checked_sub(&gas_1).unwrap(); - assert_eq!(gas_max, gas_0 + gas_per_recursion * limits::CALL_STACK_DEPTH as u64); - }); - } + // Upload the io echoing fixture for later use + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code_return_with_data, + deposit_limit::(), + )); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code_return_data_api)) + .build_and_unwrap_contract(); + + // Call the contract: It will issue calls and deploys, asserting on + assert_ok!(builder::call(addr) + .value(10 * 1024) + .data(hash_return_with_data.encode()) + .build()); + }); +} - #[test] - fn read_only_call_cannot_store() { - let (wasm_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); +#[test] +fn immutable_data_works() { + let (code, _) = compile_module("immutable_data").unwrap(); - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - // Read-only call fails when modifying storage. - assert_err_ignore_postinfo!( - builder::call(addr_caller).data((&addr_callee, 100u32).encode()).build(), - >::ContractTrapped - ); - }); - } + let data = [0xfe; 8]; - #[test] - fn read_only_call_cannot_transfer() { - let (wasm_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Create fixture: Constructor sets the immtuable data + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) + .data(data.to_vec()) + .build_and_unwrap_contract(); - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); - - // Read-only call fails when a non-zero value is set. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data( - (addr_callee, pallet_revive_uapi::CallFlags::READ_ONLY.bits(), 100u64) - .encode() - ) - .build(), - >::StateChangeDenied - ); - }); - } + // Storing immmutable data charges storage deposit; verify it explicitly. + assert_eq!( + test_utils::get_balance_on_hold( + &HoldReason::StorageDepositReserve.into(), + &::AddressMapper::to_account_id(&addr) + ), + test_utils::contract_info_storage_deposit(&addr) + ); + assert_eq!(test_utils::get_contract(&addr).immutable_data_len(), data.len() as u32); - #[test] - fn read_only_subsequent_call_cannot_store() { - let (wasm_read_only_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); - let (wasm_caller, _code_hash_caller) = compile_module("call_with_flags_and_value").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("store_call").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // Call the contract: Asserts the input to equal the immutable data + assert_ok!(builder::call(addr).data(data.to_vec()).build()); + }); +} - // Create contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_read_only_caller)) - .build_and_unwrap_contract(); - let Contract { addr: addr_subsequent_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); +#[test] +fn sbrk_cannot_be_deployed() { + let (code, _) = compile_module("sbrk").unwrap(); - // Subsequent call input. - let input = (&addr_callee, pallet_revive_uapi::CallFlags::empty().bits(), 0u64, 100u32); + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); - // Read-only call fails when modifying storage. - assert_err_ignore_postinfo!( - builder::call(addr_caller) - .data((&addr_subsequent_caller, input).encode()) - .build(), - >::ContractTrapped - ); - }); - } + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code.clone(), + deposit_limit::(), + ), + >::InvalidInstruction + ); - #[test] - fn read_only_call_works() { - let (wasm_caller, _code_hash_caller) = compile_module("read_only_call").unwrap(); - let (wasm_callee, _code_hash_callee) = compile_module("dummy").unwrap(); - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + assert_err!( + builder::bare_instantiate(Code::Upload(code)).build().result, + >::InvalidInstruction + ); + }); +} - // Create both contracts: Constructors do nothing. - let Contract { addr: addr_caller, .. } = - builder::bare_instantiate(Code::Upload(wasm_caller)).build_and_unwrap_contract(); - let Contract { addr: addr_callee, .. } = - builder::bare_instantiate(Code::Upload(wasm_callee)).build_and_unwrap_contract(); +#[test] +fn overweight_basic_block_cannot_be_deployed() { + let (code, _) = compile_module("basic_block").unwrap(); - assert_ok!(builder::call(addr_caller).data(addr_callee.encode()).build()); - }); - } + ExtBuilder::default().build().execute_with(|| { + let _ = Balances::set_balance(&ALICE, 1_000_000); - #[test] - fn create1_with_value_works() { - let (code, code_hash) = compile_module("create1_with_value").unwrap(); - let value = 42; - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + assert_err!( + Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + code.clone(), + deposit_limit::(), + ), + >::BasicBlockTooLarge + ); - // Create the contract: Constructor does nothing. - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + assert_err!( + builder::bare_instantiate(Code::Upload(code)).build().result, + >::BasicBlockTooLarge + ); + }); +} - // Call the contract: Deploys itself using create1 and the expected value - assert_ok!(builder::call(addr).value(value).data(code_hash.encode()).build()); +#[test] +fn origin_api_works() { + let (code, _) = compile_module("origin").unwrap(); - // We should see the expected balance at the expected account - let address = crate::address::create1(&addr, 0); - let account_id = ::AddressMapper::to_account_id(&address); - let usable_balance = ::Currency::usable_balance(&account_id); - assert_eq!(usable_balance, value); - }); - } + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - #[test] - fn static_data_limit_is_enforced() { - let (oom_rw_trailing, _) = compile_module("oom_rw_trailing").unwrap(); - let (oom_rw_included, _) = compile_module("oom_rw_included").unwrap(); - let (oom_ro, _) = compile_module("oom_ro").unwrap(); + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - ExtBuilder::default().build().execute_with(|| { - let _ = Balances::set_balance(&ALICE, 1_000_000); + // Call the contract: Asserts the origin API to work as expected + assert_ok!(builder::call(addr).build()); + }); +} - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - oom_rw_trailing, - deposit_limit::(), - ), - >::StaticMemoryTooLarge - ); +#[test] +fn code_hash_works() { + let (code_hash_code, self_code_hash) = compile_module("code_hash").unwrap(); + let (dummy_code, code_hash) = compile_module("dummy").unwrap(); - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - oom_rw_included, - deposit_limit::(), - ), - >::BlobTooLarge - ); + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - assert_err!( - Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - oom_ro, - deposit_limit::(), - ), - >::BlobTooLarge - ); - }); - } + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code_hash_code)).build_and_unwrap_contract(); + let Contract { addr: dummy_addr, .. } = + builder::bare_instantiate(Code::Upload(dummy_code)).build_and_unwrap_contract(); - #[test] - fn call_diverging_out_len_works() { - let (code, _) = compile_module("call_diverging_out_len").unwrap(); + // code hash of dummy contract + assert_ok!(builder::call(addr).data((dummy_addr, code_hash).encode()).build()); + // code has of itself + assert_ok!(builder::call(addr).data((addr, self_code_hash).encode()).build()); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // EOA doesn't exists + assert_err!( + builder::bare_call(addr) + .data((BOB_ADDR, crate::exec::EMPTY_CODE_HASH).encode()) + .build() + .result, + Error::::ContractTrapped + ); + // non-existing will return zero + assert_ok!(builder::call(addr).data((BOB_ADDR, H256::zero()).encode()).build()); - // Create the contract: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + // create EOA + let _ = ::Currency::set_balance( + &::AddressMapper::to_account_id(&BOB_ADDR), + 1_000_000, + ); - // Call the contract: It will issue calls and deploys, asserting on - // correct output if the supplied output length was smaller than - // than what the callee returned. - assert_ok!(builder::call(addr).build()); - }); - } + // EOA returns empty code hash + assert_ok!(builder::call(addr) + .data((BOB_ADDR, crate::exec::EMPTY_CODE_HASH).encode()) + .build()); + }); +} - #[test] - fn chain_id_works() { - let (code, _) = compile_module("chain_id").unwrap(); +#[test] +fn code_size_works() { + let (tester_code, _) = compile_module("extcodesize").unwrap(); + let tester_code_len = tester_code.len() as u64; - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let (dummy_code, _) = compile_module("dummy").unwrap(); + let dummy_code_len = dummy_code.len() as u64; - let chain_id = U256::from(::ChainId::get()); - let received = builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_result(); - assert_eq!(received.result.data, chain_id.encode()); - }); - } + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); - #[test] - fn return_data_api_works() { - let (code_return_data_api, _) = compile_module("return_data_api").unwrap(); - let (code_return_with_data, hash_return_with_data) = - compile_module("return_with_data").unwrap(); + let Contract { addr: tester_addr, .. } = + builder::bare_instantiate(Code::Upload(tester_code)).build_and_unwrap_contract(); + let Contract { addr: dummy_addr, .. } = + builder::bare_instantiate(Code::Upload(dummy_code)).build_and_unwrap_contract(); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + // code size of another contract address + assert_ok!(builder::call(tester_addr).data((dummy_addr, dummy_code_len).encode()).build()); - // Upload the io echoing fixture for later use - assert_ok!(Contracts::upload_code( - RuntimeOrigin::signed(ALICE), - code_return_with_data, - deposit_limit::(), - )); + // code size of own contract address + assert_ok!(builder::call(tester_addr) + .data((tester_addr, tester_code_len).encode()) + .build()); - // Create fixture: Constructor does nothing - let Contract { addr, .. } = - builder::bare_instantiate(Code::Upload(code_return_data_api)) - .build_and_unwrap_contract(); + // code size of non contract accounts + assert_ok!(builder::call(tester_addr).data(([8u8; 20], 0u64).encode()).build()); + }); +} - // Call the contract: It will issue calls and deploys, asserting on - assert_ok!(builder::call(addr) - .value(10 * 1024) - .data(hash_return_with_data.encode()) - .build()); - }); - } +#[test] +fn origin_must_be_mapped() { + let (code, hash) = compile_module("dummy").unwrap(); - #[test] - fn immutable_data_works() { - let (code, _) = compile_module("immutable_data").unwrap(); + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + ::Currency::set_balance(&EVE, 1_000_000); - ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let _ = ::Currency::set_balance(&ALICE, 1_000_000); + let eve = RuntimeOrigin::signed(EVE); - let data = [0xfe; 8]; + // alice can instantiate as she doesn't need a mapping + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); - // Create fixture: Constructor sets the immtuable data - let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code)) - .data(data.to_vec()) - .build_and_unwrap_contract(); + // without a mapping eve can neither call nor instantiate + assert_err!( + builder::bare_call(addr).origin(eve.clone()).build().result, + >::AccountUnmapped + ); + assert_err!( + builder::bare_instantiate(Code::Existing(hash)) + .origin(eve.clone()) + .build() + .result, + >::AccountUnmapped + ); - // Storing immmutable data charges storage deposit; verify it explicitly. - assert_eq!( - test_utils::get_balance_on_hold( - &HoldReason::StorageDepositReserve.into(), - &::AddressMapper::to_account_id(&addr) - ), - test_utils::contract_info_storage_deposit(&addr) - ); - assert_eq!(test_utils::get_contract(&addr).immutable_data_len(), data.len() as u32); + // after mapping eve is usable as an origin + >::map_account(eve.clone()).unwrap(); + assert_ok!(builder::bare_call(addr).origin(eve.clone()).build().result); + assert_ok!(builder::bare_instantiate(Code::Existing(hash)).origin(eve).build().result); + }); +} - // Call the contract: Asserts the input to equal the immutable data - assert_ok!(builder::call(addr).data(data.to_vec()).build()); - }); - } +#[test] +fn mapped_address_works() { + let (code, _) = compile_module("terminate_and_send_to_eve").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + ::Currency::set_balance(&ALICE, 1_000_000); + + // without a mapping everything will be send to the fallback account + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code.clone())).build_and_unwrap_contract(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 0); + builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); + + // after mapping it will be sent to the real eve account + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + // need some balance to pay for the map deposit + ::Currency::set_balance(&EVE, 1_000); + >::map_account(RuntimeOrigin::signed(EVE)).unwrap(); + builder::bare_call(addr).build_and_unwrap_result(); + assert_eq!(::Currency::total_balance(&EVE_FALLBACK), 100); + assert_eq!(::Currency::total_balance(&EVE), 1_100); + }); } diff --git a/substrate/frame/revive/src/tests/test_debug.rs b/substrate/frame/revive/src/tests/test_debug.rs index 1e94d5cafb81..7c4fbba71f65 100644 --- a/substrate/frame/revive/src/tests/test_debug.rs +++ b/substrate/frame/revive/src/tests/test_debug.rs @@ -23,6 +23,7 @@ use crate::{ test_utils::*, }; use frame_support::traits::Currency; +use pretty_assertions::assert_eq; use sp_core::H160; use std::cell::RefCell; @@ -99,146 +100,139 @@ impl CallSpan for TestCallSpan { } } -/// We can only run the tests if we have a riscv toolchain installed -#[cfg(feature = "riscv")] -mod run_tests { - use super::*; - use pretty_assertions::assert_eq; +#[test] +fn debugging_works() { + let (wasm_caller, _) = compile_module("call").unwrap(); + let (wasm_callee, _) = compile_module("store_call").unwrap(); - #[test] - fn debugging_works() { - let (wasm_caller, _) = compile_module("call").unwrap(); - let (wasm_callee, _) = compile_module("store_call").unwrap(); - - fn current_stack() -> Vec { - DEBUG_EXECUTION_TRACE.with(|stack| stack.borrow().clone()) - } + fn current_stack() -> Vec { + DEBUG_EXECUTION_TRACE.with(|stack| stack.borrow().clone()) + } - fn deploy(wasm: Vec) -> H160 { - Contracts::bare_instantiate( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - deposit_limit::(), - Code::Upload(wasm), - vec![], - Some([0u8; 32]), - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .addr - } + fn deploy(wasm: Vec) -> H160 { + Contracts::bare_instantiate( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + deposit_limit::(), + Code::Upload(wasm), + vec![], + Some([0u8; 32]), + DebugInfo::Skip, + CollectEvents::Skip, + ) + .result + .unwrap() + .addr + } - fn constructor_frame(contract_address: &H160, after: bool) -> DebugFrame { - DebugFrame { - contract_address: *contract_address, - call: ExportedFunction::Constructor, - input: vec![], - result: if after { Some(vec![]) } else { None }, - } + fn constructor_frame(contract_address: &H160, after: bool) -> DebugFrame { + DebugFrame { + contract_address: *contract_address, + call: ExportedFunction::Constructor, + input: vec![], + result: if after { Some(vec![]) } else { None }, } + } - fn call_frame(contract_address: &H160, args: Vec, after: bool) -> DebugFrame { - DebugFrame { - contract_address: *contract_address, - call: ExportedFunction::Call, - input: args, - result: if after { Some(vec![]) } else { None }, - } + fn call_frame(contract_address: &H160, args: Vec, after: bool) -> DebugFrame { + DebugFrame { + contract_address: *contract_address, + call: ExportedFunction::Call, + input: args, + result: if after { Some(vec![]) } else { None }, } - - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = Balances::deposit_creating(&ALICE, 1_000_000); - - assert_eq!(current_stack(), vec![]); - - let addr_caller = deploy(wasm_caller); - let addr_callee = deploy(wasm_callee); - - assert_eq!( - current_stack(), - vec![ - constructor_frame(&addr_caller, false), - constructor_frame(&addr_caller, true), - constructor_frame(&addr_callee, false), - constructor_frame(&addr_callee, true), - ] - ); - - let main_args = (100u32, &addr_callee.clone()).encode(); - let inner_args = (100u32).encode(); - - assert_ok!(Contracts::call( - RuntimeOrigin::signed(ALICE), - addr_caller, - 0, - GAS_LIMIT, - deposit_limit::(), - main_args.clone() - )); - - let stack_top = current_stack()[4..].to_vec(); - assert_eq!( - stack_top, - vec![ - call_frame(&addr_caller, main_args.clone(), false), - call_frame(&addr_callee, inner_args.clone(), false), - call_frame(&addr_callee, inner_args, true), - call_frame(&addr_caller, main_args, true), - ] - ); - }); } - #[test] - fn call_interception_works() { - let (wasm, _) = compile_module("dummy").unwrap(); - - ExtBuilder::default().existential_deposit(200).build().execute_with(|| { - let _ = Balances::deposit_creating(&ALICE, 1_000_000); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + assert_eq!(current_stack(), vec![]); + + let addr_caller = deploy(wasm_caller); + let addr_callee = deploy(wasm_callee); + + assert_eq!( + current_stack(), + vec![ + constructor_frame(&addr_caller, false), + constructor_frame(&addr_caller, true), + constructor_frame(&addr_callee, false), + constructor_frame(&addr_callee, true), + ] + ); + + let main_args = (100u32, &addr_callee.clone()).encode(); + let inner_args = (100u32).encode(); + + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller, + 0, + GAS_LIMIT, + deposit_limit::(), + main_args.clone() + )); + + let stack_top = current_stack()[4..].to_vec(); + assert_eq!( + stack_top, + vec![ + call_frame(&addr_caller, main_args.clone(), false), + call_frame(&addr_callee, inner_args.clone(), false), + call_frame(&addr_callee, inner_args, true), + call_frame(&addr_caller, main_args, true), + ] + ); + }); +} - let account_id = Contracts::bare_instantiate( - RuntimeOrigin::signed(ALICE), - 0, - GAS_LIMIT, - deposit_limit::(), - Code::Upload(wasm), - vec![], - // some salt to ensure that the address of this contract is unique among all tests - Some([0x41; 32]), - DebugInfo::Skip, - CollectEvents::Skip, - ) - .result - .unwrap() - .addr; - - // no interception yet - assert_ok!(Contracts::call( +#[test] +fn call_interception_works() { + let (wasm, _) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + let account_id = Contracts::bare_instantiate( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + deposit_limit::(), + Code::Upload(wasm), + vec![], + // some salt to ensure that the address of this contract is unique among all tests + Some([0x41; 32]), + DebugInfo::Skip, + CollectEvents::Skip, + ) + .result + .unwrap() + .addr; + + // no interception yet + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + account_id, + 0, + GAS_LIMIT, + deposit_limit::(), + vec![], + )); + + // intercept calls to this contract + INTERCEPTED_ADDRESS.with(|i| *i.borrow_mut() = Some(account_id)); + + assert_err_ignore_postinfo!( + Contracts::call( RuntimeOrigin::signed(ALICE), account_id, 0, GAS_LIMIT, deposit_limit::(), vec![], - )); - - // intercept calls to this contract - INTERCEPTED_ADDRESS.with(|i| *i.borrow_mut() = Some(account_id)); - - assert_err_ignore_postinfo!( - Contracts::call( - RuntimeOrigin::signed(ALICE), - account_id, - 0, - GAS_LIMIT, - deposit_limit::(), - vec![], - ), - >::ContractReverted, - ); - }); - } + ), + >::ContractReverted, + ); + }); } diff --git a/substrate/frame/revive/src/wasm/mod.rs b/substrate/frame/revive/src/wasm/mod.rs index cd274873975d..f10c4f5fddf8 100644 --- a/substrate/frame/revive/src/wasm/mod.rs +++ b/substrate/frame/revive/src/wasm/mod.rs @@ -26,7 +26,7 @@ pub use crate::wasm::runtime::SyscallDoc; #[cfg(test)] pub use runtime::HIGHEST_API_VERSION; -#[cfg(all(feature = "runtime-benchmarks", feature = "riscv"))] +#[cfg(feature = "runtime-benchmarks")] pub use crate::wasm::runtime::{ReturnData, TrapReason}; pub use crate::wasm::runtime::{ApiVersion, Memory, Runtime, RuntimeCosts}; @@ -48,7 +48,7 @@ use frame_support::{ ensure, traits::{fungible::MutateHold, tokens::Precision::BestEffort}, }; -use sp_core::{Get, U256}; +use sp_core::{Get, H256, U256}; use sp_runtime::DispatchError; /// Validated Wasm module ready for execution. @@ -63,7 +63,7 @@ pub struct WasmBlob { code_info: CodeInfo, // This is for not calculating the hash every time we need it. #[codec(skip)] - code_hash: sp_core::H256, + code_hash: H256, } /// Contract code related data, such as: @@ -147,14 +147,14 @@ where api_version: API_VERSION, behaviour_version: Default::default(), }; - let code_hash = sp_core::H256(sp_io::hashing::keccak_256(&code)); + let code_hash = H256(sp_io::hashing::keccak_256(&code)); Ok(WasmBlob { code, code_info, code_hash }) } /// Remove the code from storage and refund the deposit to its owner. /// /// Applies all necessary checks before removing the code. - pub fn remove(origin: &T::AccountId, code_hash: sp_core::H256) -> DispatchResult { + pub fn remove(origin: &T::AccountId, code_hash: H256) -> DispatchResult { >::try_mutate_exists(&code_hash, |existing| { if let Some(code_info) = existing { ensure!(code_info.refcount == 0, >::CodeInUse); @@ -200,7 +200,10 @@ where &self.code_info.owner, deposit, ) - .map_err(|_| >::StorageDepositNotEnoughFunds)?; + .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); @@ -245,6 +248,11 @@ impl CodeInfo { pub fn deposit(&self) -> BalanceOf { self.deposit } + + /// Returns the code length. + pub fn code_len(&self) -> U256 { + self.code_len.into() + } } pub struct PreparedCall<'a, E: Ext> { @@ -291,6 +299,7 @@ impl WasmBlob { let mut module_config = polkavm::ModuleConfig::new(); module_config.set_page_size(limits::PAGE_SIZE); module_config.set_gas_metering(Some(polkavm::GasMeteringKind::Sync)); + module_config.set_allow_sbrk(false); let module = polkavm::Module::new(&engine, &module_config, self.code.into_inner().into()) .map_err(|err| { log::debug!(target: LOG_TARGET, "failed to create polkavm module: {err:?}"); @@ -326,10 +335,7 @@ impl Executable for WasmBlob where BalanceOf: Into + TryFrom, { - fn from_storage( - code_hash: sp_core::H256, - gas_meter: &mut GasMeter, - ) -> Result { + fn from_storage(code_hash: H256, gas_meter: &mut GasMeter) -> Result { let code_info = >::get(code_hash).ok_or(Error::::CodeNotFound)?; gas_meter.charge(CodeLoadToken(code_info.code_len))?; let code = >::get(code_hash).ok_or(Error::::CodeNotFound)?; @@ -356,7 +362,7 @@ where self.code.as_ref() } - fn code_hash(&self) -> &sp_core::H256 { + fn code_hash(&self) -> &H256 { &self.code_hash } diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 485abbfda225..3e2c83db1ebd 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -44,13 +44,6 @@ type CallOf = ::RuntimeCall; /// The maximum nesting depth a contract can use when encoding types. const MAX_DECODE_NESTING: u32 = 256; -/// Encode a `U256` into a 32 byte buffer. -fn as_bytes(u: U256) -> [u8; 32] { - let mut bytes = [0u8; 32]; - u.to_little_endian(&mut bytes); - bytes -} - #[derive(Clone, Copy)] pub enum ApiVersion { /// Expose all APIs even unversioned ones. Only used for testing and benchmarking. @@ -110,6 +103,13 @@ pub trait Memory { Ok(U256::from_little_endian(&buf)) } + /// Read a `H160` from the sandbox memory. + fn read_h160(&self, ptr: u32) -> Result { + let mut buf = H160::default(); + self.read_into_buf(ptr, buf.as_bytes_mut())?; + Ok(buf) + } + /// Read a `H256` from the sandbox memory. fn read_h256(&self, ptr: u32) -> Result { let mut code_hash = H256::default(); @@ -298,12 +298,16 @@ pub enum RuntimeCosts { CopyToContract(u32), /// Weight of calling `seal_caller`. Caller, + /// Weight of calling `seal_origin`. + Origin, /// Weight of calling `seal_is_contract`. IsContract, /// Weight of calling `seal_code_hash`. CodeHash, /// Weight of calling `seal_own_code_hash`. OwnCodeHash, + /// Weight of calling `seal_code_size`. + CodeSize, /// Weight of calling `seal_caller_is_origin`. CallerIsOrigin, /// Weight of calling `caller_is_root`. @@ -322,6 +326,8 @@ pub enum RuntimeCosts { MinimumBalance, /// Weight of calling `seal_block_number`. BlockNumber, + /// Weight of calling `seal_block_hash`. + BlockHash, /// Weight of calling `seal_now`. Now, /// Weight of calling `seal_weight_to_fee`. @@ -352,8 +358,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. @@ -455,8 +459,10 @@ impl Token for RuntimeCosts { CopyToContract(len) => T::WeightInfo::seal_input(len), CopyFromContract(len) => T::WeightInfo::seal_return(len), Caller => T::WeightInfo::seal_caller(), + Origin => T::WeightInfo::seal_origin(), IsContract => T::WeightInfo::seal_is_contract(), CodeHash => T::WeightInfo::seal_code_hash(), + CodeSize => T::WeightInfo::seal_code_size(), OwnCodeHash => T::WeightInfo::seal_own_code_hash(), CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(), CallerIsRoot => T::WeightInfo::seal_caller_is_root(), @@ -467,6 +473,7 @@ impl Token for RuntimeCosts { ValueTransferred => T::WeightInfo::seal_value_transferred(), MinimumBalance => T::WeightInfo::seal_minimum_balance(), BlockNumber => T::WeightInfo::seal_block_number(), + BlockHash => T::WeightInfo::seal_block_hash(), Now => T::WeightInfo::seal_now(), WeightToFee => T::WeightInfo::seal_weight_to_fee(), Terminate(locked_dependencies) => T::WeightInfo::seal_terminate(locked_dependencies), @@ -494,7 +501,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), @@ -530,16 +536,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, } } } @@ -645,7 +652,7 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { run: impl FnOnce(&mut Self) -> DispatchResultWithPostInfo, ) -> Result { use frame_support::dispatch::extract_actual_weight; - let charged = self.charge_gas(runtime_cost(dispatch_info.weight))?; + let charged = self.charge_gas(runtime_cost(dispatch_info.call_weight))?; let result = run(self); let actual_weight = extract_actual_weight(&result, &dispatch_info); self.adjust_gas(charged, runtime_cost(actual_weight)); @@ -981,6 +988,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, @@ -988,6 +998,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))?; @@ -1000,14 +1014,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 mut callee = H160::zero(); - memory.read_into_buf(callee_ptr, callee.as_bytes_mut())?; - 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() { @@ -1028,13 +1035,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) }, }; @@ -1132,8 +1137,7 @@ impl<'a, E: Ext, M: ?Sized + Memory> Runtime<'a, E, M> { let count = self.ext.locked_delegate_dependencies_count() as _; self.charge_gas(RuntimeCosts::Terminate(count))?; - let mut beneficiary = H160::zero(); - memory.read_into_buf(beneficiary_ptr, beneficiary.as_bytes_mut())?; + let beneficiary = memory.read_h160(beneficiary_ptr)?; self.ext.terminate(&beneficiary)?; Err(TrapReason::Termination) } @@ -1228,30 +1232,6 @@ pub mod env { 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 mut callee = H160::zero(); - memory.read_into_buf(address_ptr, callee.as_bytes_mut())?; - 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)] @@ -1272,12 +1252,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, @@ -1292,7 +1270,10 @@ pub mod env { &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, @@ -1301,7 +1282,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, @@ -1395,40 +1379,58 @@ pub mod env { )?) } + /// Stores the address of the call stack origin into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::origin`]. + #[api_version(0)] + 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()?); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + origin.as_bytes(), + false, + already_charged, + )?) + } + /// 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 mut address = H160::zero(); - memory.read_into_buf(account_ptr, address.as_bytes_mut())?; + 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)] - fn code_hash( - &mut self, - memory: &mut M, - addr_ptr: u32, - out_ptr: u32, - ) -> Result { + fn code_hash(&mut self, memory: &mut M, addr_ptr: u32, out_ptr: u32) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::CodeHash)?; - let mut address = H160::zero(); - memory.read_into_buf(addr_ptr, address.as_bytes_mut())?; - if let Some(value) = self.ext.code_hash(&address) { - self.write_fixed_sandbox_output( - memory, - out_ptr, - &value.as_bytes(), - false, - already_charged, - )?; - Ok(ReturnErrorCode::Success) - } else { - Ok(ReturnErrorCode::KeyNotFound) - } + let address = memory.read_h160(addr_ptr)?; + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &self.ext.code_hash(&address).as_bytes(), + false, + already_charged, + )?) + } + + /// 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> { + 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. @@ -1557,7 +1559,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.balance()), + &self.ext.balance().to_little_endian(), false, already_charged, )?) @@ -1573,12 +1575,11 @@ pub mod env { out_ptr: u32, ) -> Result<(), TrapReason> { self.charge_gas(RuntimeCosts::BalanceOf)?; - let mut address = H160::zero(); - memory.read_into_buf(addr_ptr, address.as_bytes_mut())?; + let address = memory.read_h160(addr_ptr)?; Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.balance_of(&address)), + &self.ext.balance_of(&address).to_little_endian(), false, already_charged, )?) @@ -1591,7 +1592,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(U256::from(::ChainId::get())), + &U256::from(::ChainId::get()).to_little_endian(), false, |_| Some(RuntimeCosts::CopyToContract(32)), )?) @@ -1605,7 +1606,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.value_transferred()), + &self.ext.value_transferred().to_little_endian(), false, already_charged, )?) @@ -1619,7 +1620,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.now()), + &self.ext.now().to_little_endian(), false, already_charged, )?) @@ -1633,7 +1634,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.minimum_balance()), + &self.ext.minimum_balance().to_little_endian(), false, already_charged, )?) @@ -1687,7 +1688,28 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(self.ext.block_number()), + &self.ext.block_number().to_little_endian(), + false, + already_charged, + )?) + } + + /// Stores the block hash at given block height into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::block_hash`]. + #[api_version(0)] + fn block_hash( + &mut self, + memory: &mut M, + block_number_ptr: u32, + out_ptr: u32, + ) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::BlockHash)?; + let block_number = memory.read_u256(block_number_ptr)?; + let block_hash = self.ext.block_hash(block_number).unwrap_or(H256::zero()); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + &block_hash.as_bytes(), false, already_charged, )?) @@ -1847,7 +1869,7 @@ pub mod env { let execute_weight = <::Xcm as ExecuteController<_, _>>::WeightInfo::execute(); let weight = self.ext.gas_meter().gas_left().max(execute_weight); - let dispatch_info = DispatchInfo { weight, ..Default::default() }; + let dispatch_info = DispatchInfo { call_weight: weight, ..Default::default() }; self.call_dispatchable::( dispatch_info, @@ -2045,7 +2067,7 @@ pub mod env { Ok(self.write_fixed_sandbox_output( memory, out_ptr, - &as_bytes(U256::from(self.ext.last_frame_output().data.len())), + &U256::from(self.ext.last_frame_output().data.len()).to_little_endian(), false, |len| Some(RuntimeCosts::CopyToContract(len)), )?) diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index 5e549de3a9fb..96654432a5cc 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -18,25 +18,27 @@ //! Autogenerated weights for `pallet_revive` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-10-04, 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-jniz7bxx-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_revive +// --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_revive -// --chain=dev -// --header=./substrate/HEADER-APACHE2 // --output=./substrate/frame/revive/src/weights.rs +// --header=./substrate/HEADER-APACHE2 // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,11 +60,16 @@ pub trait WeightInfo { fn upload_code(c: u32, ) -> Weight; fn remove_code() -> Weight; fn set_code() -> Weight; + fn map_account() -> Weight; + fn unmap_account() -> Weight; + fn dispatch_as_fallback_account() -> Weight; fn noop_host_fn(r: u32, ) -> Weight; fn seal_caller() -> Weight; + fn seal_origin() -> Weight; fn seal_is_contract() -> Weight; fn seal_code_hash() -> Weight; fn seal_own_code_hash() -> Weight; + fn seal_code_size() -> Weight; fn seal_caller_is_origin() -> Weight; fn seal_caller_is_root() -> Weight; fn seal_address() -> Weight; @@ -74,6 +81,7 @@ pub trait WeightInfo { fn seal_value_transferred() -> Weight; fn seal_minimum_balance() -> 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; @@ -100,7 +108,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; @@ -126,8 +133,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_700_000 picoseconds. - Weight::from_parts(2_882_000, 1594) + // Minimum execution time: 2_818_000 picoseconds. + Weight::from_parts(3_058_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -135,18 +142,20 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `392 + k * (69 ±0)` - // Estimated: `382 + k * (70 ±0)` - // Minimum execution time: 13_819_000 picoseconds. - Weight::from_parts(14_021_000, 382) - // Standard Error: 843 - .saturating_add(Weight::from_parts(1_222_715, 0).saturating_mul(k.into())) + // Measured: `425 + k * (69 ±0)` + // Estimated: `415 + k * (70 ±0)` + // Minimum execution time: 15_916_000 picoseconds. + Weight::from_parts(16_132_000, 415) + // Standard Error: 1_482 + .saturating_add(Weight::from_parts(1_185_583, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } + /// Storage: `Revive::AddressSuffix` (r:2 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) @@ -160,17 +169,19 @@ 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: `838` - // Estimated: `4303` - // Minimum execution time: 79_748_000 picoseconds. - Weight::from_parts(82_727_773, 4303) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `1502` + // Estimated: `7442` + // Minimum execution time: 88_115_000 picoseconds. + Weight::from_parts(92_075_651, 7442) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) + /// Storage: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) @@ -183,21 +194,23 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 262144]`. fn instantiate_with_code(c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `303` - // Estimated: `6232` - // Minimum execution time: 179_270_000 picoseconds. - Weight::from_parts(149_933_578, 6232) + // Measured: `403` + // Estimated: `6326` + // Minimum execution time: 188_274_000 picoseconds. + Weight::from_parts(157_773_869, 6326) // Standard Error: 11 .saturating_add(Weight::from_parts(16, 0).saturating_mul(c.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_675, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(Weight::from_parts(4_464, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// 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: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) @@ -205,19 +218,21 @@ 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(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// The range of component `i` is `[0, 262144]`. fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `657` - // Estimated: `4111` - // Minimum execution time: 156_112_000 picoseconds. - Weight::from_parts(132_715_336, 4111) - // Standard Error: 16 - .saturating_add(Weight::from_parts(4_599, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Measured: `1296` + // Estimated: `4739` + // Minimum execution time: 158_616_000 picoseconds. + Weight::from_parts(134_329_076, 4739) + // Standard Error: 15 + .saturating_add(Weight::from_parts(4_358, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } + /// Storage: `Revive::AddressSuffix` (r:2 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) @@ -230,17 +245,17 @@ 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: `838` - // Estimated: `4303` - // Minimum execution time: 82_111_000 picoseconds. - Weight::from_parts(83_659_000, 4303) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Measured: `1502` + // Estimated: `7442` + // Minimum execution time: 134_935_000 picoseconds. + Weight::from_parts(141_040_000, 7442) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. @@ -248,23 +263,23 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 49_154_000 picoseconds. - Weight::from_parts(50_856_127, 3574) + // Minimum execution time: 51_026_000 picoseconds. + Weight::from_parts(53_309_143, 3574) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 41_347_000 picoseconds. - Weight::from_parts(42_272_000, 3750) + // Minimum execution time: 44_338_000 picoseconds. + Weight::from_parts(45_398_000, 3750) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -274,113 +289,172 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `495` - // Estimated: `6435` - // Minimum execution time: 25_234_000 picoseconds. - Weight::from_parts(26_339_000, 6435) + // Measured: `529` + // Estimated: `6469` + // Minimum execution time: 26_420_000 picoseconds. + Weight::from_parts(27_141_000, 6469) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } + /// Storage: `Revive::AddressSuffix` (r:1 w:1) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) + fn map_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 39_735_000 picoseconds. + Weight::from_parts(41_260_000, 3574) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) + /// Storage: `Revive::AddressSuffix` (r:0 w:1) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) + fn unmap_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `56` + // Estimated: `3521` + // Minimum execution time: 32_059_000 picoseconds. + Weight::from_parts(32_776_000, 3521) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `Measured`) + fn dispatch_as_fallback_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 13_553_000 picoseconds. + Weight::from_parts(14_121_000, 3610) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } /// The range of component `r` is `[0, 1600]`. fn noop_host_fn(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_509_000 picoseconds. - Weight::from_parts(9_047_452, 0) - // Standard Error: 165 - .saturating_add(Weight::from_parts(197_103, 0).saturating_mul(r.into())) + // Minimum execution time: 6_392_000 picoseconds. + Weight::from_parts(7_692_248, 0) + // Standard Error: 105 + .saturating_add(Weight::from_parts(180_036, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 257_000 picoseconds. - Weight::from_parts(300_000, 0) + // Minimum execution time: 287_000 picoseconds. + Weight::from_parts(317_000, 0) + } + fn seal_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 235_000 picoseconds. + Weight::from_parts(288_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_is_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `272` - // Estimated: `3737` - // Minimum execution time: 6_537_000 picoseconds. - Weight::from_parts(7_024_000, 3737) + // Measured: `306` + // Estimated: `3771` + // Minimum execution time: 10_101_000 picoseconds. + Weight::from_parts(10_420_000, 3771) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `369` - // Estimated: `3834` - // Minimum execution time: 7_571_000 picoseconds. - Weight::from_parts(8_060_000, 3834) + // Measured: `403` + // Estimated: `3868` + // Minimum execution time: 11_422_000 picoseconds. + Weight::from_parts(11_829_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: 254_000 picoseconds. - Weight::from_parts(281_000, 0) + // Minimum execution time: 247_000 picoseconds. + Weight::from_parts(282_000, 0) + } + /// 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`) + fn seal_code_size() -> Weight { + // Proof Size summary in bytes: + // Measured: `473` + // Estimated: `3938` + // Minimum execution time: 14_856_000 picoseconds. + Weight::from_parts(15_528_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: 279_000 picoseconds. - Weight::from_parts(338_000, 0) + // Minimum execution time: 303_000 picoseconds. + Weight::from_parts(361_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 240_000 picoseconds. - Weight::from_parts(286_000, 0) + // Minimum execution time: 253_000 picoseconds. + Weight::from_parts(287_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 198_000 picoseconds. - Weight::from_parts(262_000, 0) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(263_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 593_000 picoseconds. - Weight::from_parts(665_000, 0) + // Minimum execution time: 628_000 picoseconds. + Weight::from_parts(697_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `140` + // Measured: `103` // Estimated: `0` - // Minimum execution time: 5_393_000 picoseconds. - Weight::from_parts(5_688_000, 0) + // Minimum execution time: 4_531_000 picoseconds. + Weight::from_parts(4_726_000, 0) } + /// Storage: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn seal_balance_of() -> Weight { // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 3_907_000 picoseconds. - Weight::from_parts(4_154_000, 3517) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `264` + // Estimated: `3729` + // Minimum execution time: 8_787_000 picoseconds. + Weight::from_parts(9_175_000, 3729) + .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) /// The range of component `n` is `[1, 4096]`. fn seal_get_immutable_data(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `205 + n * (1 ±0)` - // Estimated: `3670 + n * (1 ±0)` - // Minimum execution time: 5_700_000 picoseconds. - Weight::from_parts(6_362_270, 3670) + // Measured: `238 + n * (1 ±0)` + // Estimated: `3703 + n * (1 ±0)` + // Minimum execution time: 5_760_000 picoseconds. + Weight::from_parts(6_591_336, 3703) // Standard Error: 4 - .saturating_add(Weight::from_parts(749, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(628, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -391,70 +465,79 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_041_000 picoseconds. - Weight::from_parts(2_216_694, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(620, 0).saturating_mul(n.into())) + // Minimum execution time: 1_971_000 picoseconds. + Weight::from_parts(2_206_252, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(529, 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: 229_000 picoseconds. - Weight::from_parts(261_000, 0) + // Minimum execution time: 246_000 picoseconds. + Weight::from_parts(279_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 226_000 picoseconds. - Weight::from_parts(270_000, 0) + // Minimum execution time: 223_000 picoseconds. + Weight::from_parts(274_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 215_000 picoseconds. - Weight::from_parts(273_000, 0) + // Minimum execution time: 213_000 picoseconds. + Weight::from_parts(270_000, 0) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `Measured`) + fn seal_block_hash() -> Weight { + // Proof Size summary in bytes: + // Measured: `30` + // Estimated: `3495` + // Minimum execution time: 3_502_000 picoseconds. + Weight::from_parts(3_777_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: 242_000 picoseconds. - Weight::from_parts(271_000, 0) + // Minimum execution time: 232_000 picoseconds. + Weight::from_parts(277_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_438_000 picoseconds. - Weight::from_parts(5_695_000, 1552) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_293_000 picoseconds. + Weight::from_parts(1_426_000, 0) } /// The range of component `n` is `[0, 262140]`. fn seal_input(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 405_000 picoseconds. - Weight::from_parts(539_737, 0) + // Minimum execution time: 449_000 picoseconds. + Weight::from_parts(446_268, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(148, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(113, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262140]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 222_000 picoseconds. - Weight::from_parts(539_301, 0) + // Minimum execution time: 244_000 picoseconds. + Weight::from_parts(612_733, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(294, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(200, 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`) /// Storage: `Revive::DeletionQueueCounter` (r:1 w:1) /// Proof: `Revive::DeletionQueueCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:33 w:33) @@ -466,13 +549,13 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 32]`. fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `272 + n * (88 ±0)` - // Estimated: `3738 + n * (2563 ±0)` - // Minimum execution time: 15_971_000 picoseconds. - Weight::from_parts(18_759_349, 3738) - // Standard Error: 10_298 - .saturating_add(Weight::from_parts(4_194_635, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Measured: `324 + n * (88 ±0)` + // Estimated: `3789 + n * (2563 ±0)` + // Minimum execution time: 21_822_000 picoseconds. + Weight::from_parts(22_468_601, 3789) + // Standard Error: 7_303 + .saturating_add(Weight::from_parts(4_138_073, 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)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -484,22 +567,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_341_000 picoseconds. - Weight::from_parts(4_292_048, 0) - // Standard Error: 2_476 - .saturating_add(Weight::from_parts(193_480, 0).saturating_mul(t.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(959, 0).saturating_mul(n.into())) + // Minimum execution time: 4_127_000 picoseconds. + Weight::from_parts(4_043_097, 0) + // Standard Error: 3_136 + .saturating_add(Weight::from_parts(209_603, 0).saturating_mul(t.into())) + // Standard Error: 28 + .saturating_add(Weight::from_parts(988, 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: 287_000 picoseconds. - Weight::from_parts(758_020, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(814, 0).saturating_mul(i.into())) + // Minimum execution time: 276_000 picoseconds. + Weight::from_parts(1_111_301, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(706, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -507,8 +590,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 7_944_000 picoseconds. - Weight::from_parts(8_358_000, 744) + // Minimum execution time: 7_869_000 picoseconds. + Weight::from_parts(8_190_000, 744) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -517,8 +600,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 44_950_000 picoseconds. - Weight::from_parts(45_575_000, 10754) + // Minimum execution time: 42_793_000 picoseconds. + Weight::from_parts(43_861_000, 10754) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -527,8 +610,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 9_095_000 picoseconds. - Weight::from_parts(9_484_000, 744) + // Minimum execution time: 8_753_000 picoseconds. + Weight::from_parts(9_235_000, 744) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -538,8 +621,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 46_814_000 picoseconds. - Weight::from_parts(47_710_000, 10754) + // Minimum execution time: 44_446_000 picoseconds. + Weight::from_parts(45_586_000, 10754) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -551,12 +634,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 9_496_000 picoseconds. - Weight::from_parts(9_875_533, 247) - // Standard Error: 34 - .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) - // Standard Error: 34 - .saturating_add(Weight::from_parts(777, 0).saturating_mul(o.into())) + // Minimum execution time: 9_214_000 picoseconds. + Weight::from_parts(9_888_060, 247) + // Standard Error: 41 + .saturating_add(Weight::from_parts(151, 0).saturating_mul(n.into())) + // Standard Error: 41 + .saturating_add(Weight::from_parts(315, 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())) @@ -568,10 +651,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_185_000 picoseconds. - Weight::from_parts(9_912_715, 247) - // Standard Error: 59 - .saturating_add(Weight::from_parts(567, 0).saturating_mul(n.into())) + // Minimum execution time: 8_647_000 picoseconds. + Weight::from_parts(9_553_009, 247) + // Standard Error: 48 + .saturating_add(Weight::from_parts(651, 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())) @@ -583,10 +666,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_586_000 picoseconds. - Weight::from_parts(9_536_041, 247) - // Standard Error: 54 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) + // Minimum execution time: 8_457_000 picoseconds. + Weight::from_parts(9_199_745, 247) + // Standard Error: 59 + .saturating_add(Weight::from_parts(1_562, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -597,10 +680,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_162_000 picoseconds. - Weight::from_parts(8_813_128, 247) - // Standard Error: 43 - .saturating_add(Weight::from_parts(880, 0).saturating_mul(n.into())) + // Minimum execution time: 8_025_000 picoseconds. + Weight::from_parts(8_700_911, 247) + // Standard Error: 49 + .saturating_add(Weight::from_parts(635, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -611,10 +694,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_717_000 picoseconds. - Weight::from_parts(10_635_621, 247) - // Standard Error: 58 - .saturating_add(Weight::from_parts(1_430, 0).saturating_mul(n.into())) + // Minimum execution time: 9_346_000 picoseconds. + Weight::from_parts(10_297_284, 247) + // Standard Error: 62 + .saturating_add(Weight::from_parts(1_396, 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())) @@ -623,36 +706,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_503_000 picoseconds. - Weight::from_parts(1_592_000, 0) + // Minimum execution time: 1_428_000 picoseconds. + Weight::from_parts(1_517_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_903_000 picoseconds. - Weight::from_parts(1_996_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(1_942_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_432_000 picoseconds. - Weight::from_parts(1_534_000, 0) + // Minimum execution time: 1_403_000 picoseconds. + Weight::from_parts(1_539_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_669_000, 0) + // Minimum execution time: 1_676_000 picoseconds. + Weight::from_parts(1_760_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 960_000 picoseconds. - Weight::from_parts(1_089_000, 0) + // Minimum execution time: 1_119_000 picoseconds. + Weight::from_parts(1_205_000, 0) } /// The range of component `n` is `[0, 512]`. /// The range of component `o` is `[0, 512]`. @@ -660,81 +743,77 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_317_000 picoseconds. - Weight::from_parts(2_449_933, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(315, 0).saturating_mul(n.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(o.into())) + // Minimum execution time: 2_146_000 picoseconds. + Weight::from_parts(2_315_339, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(327, 0).saturating_mul(n.into())) + // Standard Error: 13 + .saturating_add(Weight::from_parts(366, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 512]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_980_000 picoseconds. - Weight::from_parts(2_352_243, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(372, 0).saturating_mul(n.into())) + // Minimum execution time: 1_950_000 picoseconds. + Weight::from_parts(2_271_073, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(373, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_857_000 picoseconds. - Weight::from_parts(2_082_050, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(373, 0).saturating_mul(n.into())) + // Minimum execution time: 1_839_000 picoseconds. + Weight::from_parts(2_049_659, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(291, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_693_000 picoseconds. - Weight::from_parts(1_892_600, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(193, 0).saturating_mul(n.into())) + // Minimum execution time: 1_716_000 picoseconds. + Weight::from_parts(1_893_932, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(172, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. - fn seal_take_transient_storage(n: u32, ) -> Weight { + fn seal_take_transient_storage(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_620_000 picoseconds. - Weight::from_parts(2_818_388, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(39, 0).saturating_mul(n.into())) - } - fn seal_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `0` - // Minimum execution time: 10_207_000 picoseconds. - Weight::from_parts(10_627_000, 0) + // Minimum execution time: 2_448_000 picoseconds. + Weight::from_parts(2_676_764, 0) } + /// Storage: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// 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`) + /// 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: `630 + t * (140 ±0)` - // Estimated: `4095 + t * (140 ±0)` - // Minimum execution time: 34_452_000 picoseconds. - Weight::from_parts(34_837_900, 4095) - // Standard Error: 30_385 - .saturating_add(Weight::from_parts(1_981_565, 0).saturating_mul(t.into())) + // Measured: `1294 + t * (242 ±0)` + // Estimated: `4759 + t * (2501 ±0)` + // Minimum execution time: 39_786_000 picoseconds. + Weight::from_parts(41_175_457, 4759) + // Standard Error: 45_251 + .saturating_add(Weight::from_parts(2_375_617, 0).saturating_mul(t.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(Weight::from_parts(2, 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, 140).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2501).saturating_mul(t.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -742,10 +821,10 @@ impl WeightInfo for SubstrateWeight { /// 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: `457` - // Estimated: `3922` - // Minimum execution time: 27_287_000 picoseconds. - Weight::from_parts(28_450_000, 3922) + // Measured: `1064` + // Estimated: `4529` + // Minimum execution time: 29_762_000 picoseconds. + Weight::from_parts(31_345_000, 4529) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -759,12 +838,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: `703` - // Estimated: `4160` - // Minimum execution time: 118_660_000 picoseconds. - Weight::from_parts(104_638_796, 4160) + // Measured: `1310` + // Estimated: `4748` + // Minimum execution time: 117_791_000 picoseconds. + Weight::from_parts(105_413_907, 4748) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_296, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_038, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -773,73 +852,73 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 683_000 picoseconds. - Weight::from_parts(3_836_563, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) + // Minimum execution time: 638_000 picoseconds. + Weight::from_parts(4_703_710, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_349, 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_082_000 picoseconds. - Weight::from_parts(5_027_764, 0) + // Minimum execution time: 1_085_000 picoseconds. + Weight::from_parts(3_630_716, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_644, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_567, 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: 660_000 picoseconds. - Weight::from_parts(3_585_640, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_586, 0).saturating_mul(n.into())) + // Minimum execution time: 643_000 picoseconds. + Weight::from_parts(3_733_026, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_492, 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: 638_000 picoseconds. - Weight::from_parts(3_763_242, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(4_627_285, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(1_582, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_478, 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: 42_962_000 picoseconds. - Weight::from_parts(27_938_396, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(5_269, 0).saturating_mul(n.into())) + // Minimum execution time: 45_786_000 picoseconds. + Weight::from_parts(36_383_470, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(5_396, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 47_133_000 picoseconds. - Weight::from_parts(48_458_000, 0) + // Minimum execution time: 48_140_000 picoseconds. + Weight::from_parts(49_720_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_249_000 picoseconds. - Weight::from_parts(13_518_000, 0) + // Minimum execution time: 12_565_000 picoseconds. + Weight::from_parts(12_704_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn seal_set_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `266` - // Estimated: `3731` - // Minimum execution time: 14_696_000 picoseconds. - Weight::from_parts(15_106_000, 3731) + // Measured: `300` + // Estimated: `3765` + // Minimum execution time: 17_208_000 picoseconds. + Weight::from_parts(18_307_000, 3765) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -847,10 +926,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: `304` - // Estimated: `3769` - // Minimum execution time: 10_292_000 picoseconds. - Weight::from_parts(10_670_000, 3769) + // Measured: `338` + // Estimated: `3803` + // Minimum execution time: 13_686_000 picoseconds. + Weight::from_parts(14_186_000, 3803) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -858,10 +937,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: `304` + // Measured: `338` // Estimated: `3561` - // Minimum execution time: 9_056_000 picoseconds. - Weight::from_parts(9_350_000, 3561) + // Minimum execution time: 12_381_000 picoseconds. + Weight::from_parts(13_208_000, 3561) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -870,10 +949,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_145_000 picoseconds. - Weight::from_parts(10_744_073, 0) - // Standard Error: 72 - .saturating_add(Weight::from_parts(84_813, 0).saturating_mul(r.into())) + // Minimum execution time: 8_118_000 picoseconds. + Weight::from_parts(9_813_514, 0) + // Standard Error: 40 + .saturating_add(Weight::from_parts(71_154, 0).saturating_mul(r.into())) } } @@ -885,8 +964,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 2_700_000 picoseconds. - Weight::from_parts(2_882_000, 1594) + // Minimum execution time: 2_818_000 picoseconds. + Weight::from_parts(3_058_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -894,18 +973,20 @@ impl WeightInfo for () { /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `392 + k * (69 ±0)` - // Estimated: `382 + k * (70 ±0)` - // Minimum execution time: 13_819_000 picoseconds. - Weight::from_parts(14_021_000, 382) - // Standard Error: 843 - .saturating_add(Weight::from_parts(1_222_715, 0).saturating_mul(k.into())) + // Measured: `425 + k * (69 ±0)` + // Estimated: `415 + k * (70 ±0)` + // Minimum execution time: 15_916_000 picoseconds. + Weight::from_parts(16_132_000, 415) + // Standard Error: 1_482 + .saturating_add(Weight::from_parts(1_185_583, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(k.into())) } + /// Storage: `Revive::AddressSuffix` (r:2 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) @@ -919,17 +1000,19 @@ 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: `838` - // Estimated: `4303` - // Minimum execution time: 79_748_000 picoseconds. - Weight::from_parts(82_727_773, 4303) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `1502` + // Estimated: `7442` + // Minimum execution time: 88_115_000 picoseconds. + Weight::from_parts(92_075_651, 7442) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Balances::Holds` (r:2 w:2) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) + /// Storage: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) @@ -942,21 +1025,23 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn instantiate_with_code(c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `303` - // Estimated: `6232` - // Minimum execution time: 179_270_000 picoseconds. - Weight::from_parts(149_933_578, 6232) + // Measured: `403` + // Estimated: `6326` + // Minimum execution time: 188_274_000 picoseconds. + Weight::from_parts(157_773_869, 6326) // Standard Error: 11 .saturating_add(Weight::from_parts(16, 0).saturating_mul(c.into())) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_675, 0).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(Weight::from_parts(4_464, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// 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: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) @@ -964,19 +1049,21 @@ 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(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// The range of component `i` is `[0, 262144]`. fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `657` - // Estimated: `4111` - // Minimum execution time: 156_112_000 picoseconds. - Weight::from_parts(132_715_336, 4111) - // Standard Error: 16 - .saturating_add(Weight::from_parts(4_599, 0).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Measured: `1296` + // Estimated: `4739` + // Minimum execution time: 158_616_000 picoseconds. + Weight::from_parts(134_329_076, 4739) + // Standard Error: 15 + .saturating_add(Weight::from_parts(4_358, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } + /// Storage: `Revive::AddressSuffix` (r:2 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `Revive::ContractInfoOf` (r:1 w:1) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:1 w:0) @@ -989,17 +1076,17 @@ 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: `838` - // Estimated: `4303` - // Minimum execution time: 82_111_000 picoseconds. - Weight::from_parts(83_659_000, 4303) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Measured: `1502` + // Estimated: `7442` + // Minimum execution time: 134_935_000 picoseconds. + Weight::from_parts(141_040_000, 7442) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. @@ -1007,23 +1094,23 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 49_154_000 picoseconds. - Weight::from_parts(50_856_127, 3574) + // Minimum execution time: 51_026_000 picoseconds. + Weight::from_parts(53_309_143, 3574) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) /// Storage: `Balances::Holds` (r:1 w:1) - /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(337), added: 2812, mode: `Measured`) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) /// Storage: `Revive::PristineCode` (r:0 w:1) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) fn remove_code() -> Weight { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 41_347_000 picoseconds. - Weight::from_parts(42_272_000, 3750) + // Minimum execution time: 44_338_000 picoseconds. + Weight::from_parts(45_398_000, 3750) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1033,113 +1120,172 @@ impl WeightInfo for () { /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn set_code() -> Weight { // Proof Size summary in bytes: - // Measured: `495` - // Estimated: `6435` - // Minimum execution time: 25_234_000 picoseconds. - Weight::from_parts(26_339_000, 6435) + // Measured: `529` + // Estimated: `6469` + // Minimum execution time: 26_420_000 picoseconds. + Weight::from_parts(27_141_000, 6469) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } + /// Storage: `Revive::AddressSuffix` (r:1 w:1) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) + fn map_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3574` + // Minimum execution time: 39_735_000 picoseconds. + Weight::from_parts(41_260_000, 3574) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `Measured`) + /// Storage: `Revive::AddressSuffix` (r:0 w:1) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) + fn unmap_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `56` + // Estimated: `3521` + // Minimum execution time: 32_059_000 picoseconds. + Weight::from_parts(32_776_000, 3521) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `SafeMode::EnteredUntil` (r:1 w:0) + /// Proof: `SafeMode::EnteredUntil` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) + /// Storage: `TxPause::PausedCalls` (r:1 w:0) + /// Proof: `TxPause::PausedCalls` (`max_values`: None, `max_size`: Some(532), added: 3007, mode: `Measured`) + fn dispatch_as_fallback_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 13_553_000 picoseconds. + Weight::from_parts(14_121_000, 3610) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } /// The range of component `r` is `[0, 1600]`. fn noop_host_fn(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_509_000 picoseconds. - Weight::from_parts(9_047_452, 0) - // Standard Error: 165 - .saturating_add(Weight::from_parts(197_103, 0).saturating_mul(r.into())) + // Minimum execution time: 6_392_000 picoseconds. + Weight::from_parts(7_692_248, 0) + // Standard Error: 105 + .saturating_add(Weight::from_parts(180_036, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 257_000 picoseconds. - Weight::from_parts(300_000, 0) + // Minimum execution time: 287_000 picoseconds. + Weight::from_parts(317_000, 0) + } + fn seal_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 235_000 picoseconds. + Weight::from_parts(288_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_is_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `272` - // Estimated: `3737` - // Minimum execution time: 6_537_000 picoseconds. - Weight::from_parts(7_024_000, 3737) + // Measured: `306` + // Estimated: `3771` + // Minimum execution time: 10_101_000 picoseconds. + Weight::from_parts(10_420_000, 3771) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) fn seal_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `369` - // Estimated: `3834` - // Minimum execution time: 7_571_000 picoseconds. - Weight::from_parts(8_060_000, 3834) + // Measured: `403` + // Estimated: `3868` + // Minimum execution time: 11_422_000 picoseconds. + Weight::from_parts(11_829_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: 254_000 picoseconds. - Weight::from_parts(281_000, 0) + // Minimum execution time: 247_000 picoseconds. + Weight::from_parts(282_000, 0) + } + /// 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`) + fn seal_code_size() -> Weight { + // Proof Size summary in bytes: + // Measured: `473` + // Estimated: `3938` + // Minimum execution time: 14_856_000 picoseconds. + Weight::from_parts(15_528_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: 279_000 picoseconds. - Weight::from_parts(338_000, 0) + // Minimum execution time: 303_000 picoseconds. + Weight::from_parts(361_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 240_000 picoseconds. - Weight::from_parts(286_000, 0) + // Minimum execution time: 253_000 picoseconds. + Weight::from_parts(287_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 198_000 picoseconds. - Weight::from_parts(262_000, 0) + // Minimum execution time: 231_000 picoseconds. + Weight::from_parts(263_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 593_000 picoseconds. - Weight::from_parts(665_000, 0) + // Minimum execution time: 628_000 picoseconds. + Weight::from_parts(697_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `140` + // Measured: `103` // Estimated: `0` - // Minimum execution time: 5_393_000 picoseconds. - Weight::from_parts(5_688_000, 0) + // Minimum execution time: 4_531_000 picoseconds. + Weight::from_parts(4_726_000, 0) } + /// Storage: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn seal_balance_of() -> Weight { // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 3_907_000 picoseconds. - Weight::from_parts(4_154_000, 3517) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `264` + // Estimated: `3729` + // Minimum execution time: 8_787_000 picoseconds. + Weight::from_parts(9_175_000, 3729) + .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) /// Proof: `Revive::ImmutableDataOf` (`max_values`: None, `max_size`: Some(4118), added: 6593, mode: `Measured`) /// The range of component `n` is `[1, 4096]`. fn seal_get_immutable_data(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `205 + n * (1 ±0)` - // Estimated: `3670 + n * (1 ±0)` - // Minimum execution time: 5_700_000 picoseconds. - Weight::from_parts(6_362_270, 3670) + // Measured: `238 + n * (1 ±0)` + // Estimated: `3703 + n * (1 ±0)` + // Minimum execution time: 5_760_000 picoseconds. + Weight::from_parts(6_591_336, 3703) // Standard Error: 4 - .saturating_add(Weight::from_parts(749, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(628, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1150,70 +1296,79 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_041_000 picoseconds. - Weight::from_parts(2_216_694, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(620, 0).saturating_mul(n.into())) + // Minimum execution time: 1_971_000 picoseconds. + Weight::from_parts(2_206_252, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(529, 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: 229_000 picoseconds. - Weight::from_parts(261_000, 0) + // Minimum execution time: 246_000 picoseconds. + Weight::from_parts(279_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 226_000 picoseconds. - Weight::from_parts(270_000, 0) + // Minimum execution time: 223_000 picoseconds. + Weight::from_parts(274_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 215_000 picoseconds. - Weight::from_parts(273_000, 0) + // Minimum execution time: 213_000 picoseconds. + Weight::from_parts(270_000, 0) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `Measured`) + fn seal_block_hash() -> Weight { + // Proof Size summary in bytes: + // Measured: `30` + // Estimated: `3495` + // Minimum execution time: 3_502_000 picoseconds. + Weight::from_parts(3_777_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: 242_000 picoseconds. - Weight::from_parts(271_000, 0) + // Minimum execution time: 232_000 picoseconds. + Weight::from_parts(277_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_438_000 picoseconds. - Weight::from_parts(5_695_000, 1552) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_293_000 picoseconds. + Weight::from_parts(1_426_000, 0) } /// The range of component `n` is `[0, 262140]`. fn seal_input(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 405_000 picoseconds. - Weight::from_parts(539_737, 0) + // Minimum execution time: 449_000 picoseconds. + Weight::from_parts(446_268, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(148, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(113, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262140]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 222_000 picoseconds. - Weight::from_parts(539_301, 0) + // Minimum execution time: 244_000 picoseconds. + Weight::from_parts(612_733, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(294, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(200, 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`) /// Storage: `Revive::DeletionQueueCounter` (r:1 w:1) /// Proof: `Revive::DeletionQueueCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `Measured`) /// Storage: `Revive::CodeInfoOf` (r:33 w:33) @@ -1225,13 +1380,13 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 32]`. fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `272 + n * (88 ±0)` - // Estimated: `3738 + n * (2563 ±0)` - // Minimum execution time: 15_971_000 picoseconds. - Weight::from_parts(18_759_349, 3738) - // Standard Error: 10_298 - .saturating_add(Weight::from_parts(4_194_635, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Measured: `324 + n * (88 ±0)` + // Estimated: `3789 + n * (2563 ±0)` + // Minimum execution time: 21_822_000 picoseconds. + Weight::from_parts(22_468_601, 3789) + // Standard Error: 7_303 + .saturating_add(Weight::from_parts(4_138_073, 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)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -1243,22 +1398,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_341_000 picoseconds. - Weight::from_parts(4_292_048, 0) - // Standard Error: 2_476 - .saturating_add(Weight::from_parts(193_480, 0).saturating_mul(t.into())) - // Standard Error: 22 - .saturating_add(Weight::from_parts(959, 0).saturating_mul(n.into())) + // Minimum execution time: 4_127_000 picoseconds. + Weight::from_parts(4_043_097, 0) + // Standard Error: 3_136 + .saturating_add(Weight::from_parts(209_603, 0).saturating_mul(t.into())) + // Standard Error: 28 + .saturating_add(Weight::from_parts(988, 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: 287_000 picoseconds. - Weight::from_parts(758_020, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(814, 0).saturating_mul(i.into())) + // Minimum execution time: 276_000 picoseconds. + Weight::from_parts(1_111_301, 0) + // Standard Error: 0 + .saturating_add(Weight::from_parts(706, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -1266,8 +1421,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 7_944_000 picoseconds. - Weight::from_parts(8_358_000, 744) + // Minimum execution time: 7_869_000 picoseconds. + Weight::from_parts(8_190_000, 744) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1276,8 +1431,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 44_950_000 picoseconds. - Weight::from_parts(45_575_000, 10754) + // Minimum execution time: 42_793_000 picoseconds. + Weight::from_parts(43_861_000, 10754) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1286,8 +1441,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 9_095_000 picoseconds. - Weight::from_parts(9_484_000, 744) + // Minimum execution time: 8_753_000 picoseconds. + Weight::from_parts(9_235_000, 744) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1297,8 +1452,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 46_814_000 picoseconds. - Weight::from_parts(47_710_000, 10754) + // Minimum execution time: 44_446_000 picoseconds. + Weight::from_parts(45_586_000, 10754) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1310,12 +1465,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 9_496_000 picoseconds. - Weight::from_parts(9_875_533, 247) - // Standard Error: 34 - .saturating_add(Weight::from_parts(712, 0).saturating_mul(n.into())) - // Standard Error: 34 - .saturating_add(Weight::from_parts(777, 0).saturating_mul(o.into())) + // Minimum execution time: 9_214_000 picoseconds. + Weight::from_parts(9_888_060, 247) + // Standard Error: 41 + .saturating_add(Weight::from_parts(151, 0).saturating_mul(n.into())) + // Standard Error: 41 + .saturating_add(Weight::from_parts(315, 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())) @@ -1327,10 +1482,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_185_000 picoseconds. - Weight::from_parts(9_912_715, 247) - // Standard Error: 59 - .saturating_add(Weight::from_parts(567, 0).saturating_mul(n.into())) + // Minimum execution time: 8_647_000 picoseconds. + Weight::from_parts(9_553_009, 247) + // Standard Error: 48 + .saturating_add(Weight::from_parts(651, 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())) @@ -1342,10 +1497,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_586_000 picoseconds. - Weight::from_parts(9_536_041, 247) - // Standard Error: 54 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) + // Minimum execution time: 8_457_000 picoseconds. + Weight::from_parts(9_199_745, 247) + // Standard Error: 59 + .saturating_add(Weight::from_parts(1_562, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1356,10 +1511,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_162_000 picoseconds. - Weight::from_parts(8_813_128, 247) - // Standard Error: 43 - .saturating_add(Weight::from_parts(880, 0).saturating_mul(n.into())) + // Minimum execution time: 8_025_000 picoseconds. + Weight::from_parts(8_700_911, 247) + // Standard Error: 49 + .saturating_add(Weight::from_parts(635, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1370,10 +1525,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 9_717_000 picoseconds. - Weight::from_parts(10_635_621, 247) - // Standard Error: 58 - .saturating_add(Weight::from_parts(1_430, 0).saturating_mul(n.into())) + // Minimum execution time: 9_346_000 picoseconds. + Weight::from_parts(10_297_284, 247) + // Standard Error: 62 + .saturating_add(Weight::from_parts(1_396, 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())) @@ -1382,36 +1537,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_503_000 picoseconds. - Weight::from_parts(1_592_000, 0) + // Minimum execution time: 1_428_000 picoseconds. + Weight::from_parts(1_517_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_903_000 picoseconds. - Weight::from_parts(1_996_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(1_942_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_432_000 picoseconds. - Weight::from_parts(1_534_000, 0) + // Minimum execution time: 1_403_000 picoseconds. + Weight::from_parts(1_539_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_669_000, 0) + // Minimum execution time: 1_676_000 picoseconds. + Weight::from_parts(1_760_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 960_000 picoseconds. - Weight::from_parts(1_089_000, 0) + // Minimum execution time: 1_119_000 picoseconds. + Weight::from_parts(1_205_000, 0) } /// The range of component `n` is `[0, 512]`. /// The range of component `o` is `[0, 512]`. @@ -1419,81 +1574,77 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_317_000 picoseconds. - Weight::from_parts(2_449_933, 0) - // Standard Error: 11 - .saturating_add(Weight::from_parts(315, 0).saturating_mul(n.into())) - // Standard Error: 11 - .saturating_add(Weight::from_parts(387, 0).saturating_mul(o.into())) + // Minimum execution time: 2_146_000 picoseconds. + Weight::from_parts(2_315_339, 0) + // Standard Error: 13 + .saturating_add(Weight::from_parts(327, 0).saturating_mul(n.into())) + // Standard Error: 13 + .saturating_add(Weight::from_parts(366, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 512]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_980_000 picoseconds. - Weight::from_parts(2_352_243, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(372, 0).saturating_mul(n.into())) + // Minimum execution time: 1_950_000 picoseconds. + Weight::from_parts(2_271_073, 0) + // Standard Error: 15 + .saturating_add(Weight::from_parts(373, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_857_000 picoseconds. - Weight::from_parts(2_082_050, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(373, 0).saturating_mul(n.into())) + // Minimum execution time: 1_839_000 picoseconds. + Weight::from_parts(2_049_659, 0) + // Standard Error: 14 + .saturating_add(Weight::from_parts(291, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_693_000 picoseconds. - Weight::from_parts(1_892_600, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(193, 0).saturating_mul(n.into())) + // Minimum execution time: 1_716_000 picoseconds. + Weight::from_parts(1_893_932, 0) + // Standard Error: 12 + .saturating_add(Weight::from_parts(172, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. - fn seal_take_transient_storage(n: u32, ) -> Weight { + fn seal_take_transient_storage(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_620_000 picoseconds. - Weight::from_parts(2_818_388, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(39, 0).saturating_mul(n.into())) - } - fn seal_transfer() -> Weight { - // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `0` - // Minimum execution time: 10_207_000 picoseconds. - Weight::from_parts(10_627_000, 0) + // Minimum execution time: 2_448_000 picoseconds. + Weight::from_parts(2_676_764, 0) } + /// Storage: `Revive::AddressSuffix` (r:1 w:0) + /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) /// 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`) + /// 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: `630 + t * (140 ±0)` - // Estimated: `4095 + t * (140 ±0)` - // Minimum execution time: 34_452_000 picoseconds. - Weight::from_parts(34_837_900, 4095) - // Standard Error: 30_385 - .saturating_add(Weight::from_parts(1_981_565, 0).saturating_mul(t.into())) + // Measured: `1294 + t * (242 ±0)` + // Estimated: `4759 + t * (2501 ±0)` + // Minimum execution time: 39_786_000 picoseconds. + Weight::from_parts(41_175_457, 4759) + // Standard Error: 45_251 + .saturating_add(Weight::from_parts(2_375_617, 0).saturating_mul(t.into())) // Standard Error: 0 - .saturating_add(Weight::from_parts(3, 0).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(Weight::from_parts(2, 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, 140).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 2501).saturating_mul(t.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1501,10 +1652,10 @@ impl WeightInfo for () { /// 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: `457` - // Estimated: `3922` - // Minimum execution time: 27_287_000 picoseconds. - Weight::from_parts(28_450_000, 3922) + // Measured: `1064` + // Estimated: `4529` + // Minimum execution time: 29_762_000 picoseconds. + Weight::from_parts(31_345_000, 4529) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -1518,12 +1669,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn seal_instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `703` - // Estimated: `4160` - // Minimum execution time: 118_660_000 picoseconds. - Weight::from_parts(104_638_796, 4160) + // Measured: `1310` + // Estimated: `4748` + // Minimum execution time: 117_791_000 picoseconds. + Weight::from_parts(105_413_907, 4748) // Standard Error: 11 - .saturating_add(Weight::from_parts(4_296, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(4_038, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1532,73 +1683,73 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 683_000 picoseconds. - Weight::from_parts(3_836_563, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_456, 0).saturating_mul(n.into())) + // Minimum execution time: 638_000 picoseconds. + Weight::from_parts(4_703_710, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_349, 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_082_000 picoseconds. - Weight::from_parts(5_027_764, 0) + // Minimum execution time: 1_085_000 picoseconds. + Weight::from_parts(3_630_716, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(3_644, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(3_567, 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: 660_000 picoseconds. - Weight::from_parts(3_585_640, 0) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_586, 0).saturating_mul(n.into())) + // Minimum execution time: 643_000 picoseconds. + Weight::from_parts(3_733_026, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_492, 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: 638_000 picoseconds. - Weight::from_parts(3_763_242, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(4_627_285, 0) // Standard Error: 3 - .saturating_add(Weight::from_parts(1_582, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(1_478, 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: 42_962_000 picoseconds. - Weight::from_parts(27_938_396, 0) - // Standard Error: 13 - .saturating_add(Weight::from_parts(5_269, 0).saturating_mul(n.into())) + // Minimum execution time: 45_786_000 picoseconds. + Weight::from_parts(36_383_470, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(5_396, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 47_133_000 picoseconds. - Weight::from_parts(48_458_000, 0) + // Minimum execution time: 48_140_000 picoseconds. + Weight::from_parts(49_720_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_249_000 picoseconds. - Weight::from_parts(13_518_000, 0) + // Minimum execution time: 12_565_000 picoseconds. + Weight::from_parts(12_704_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) fn seal_set_code_hash() -> Weight { // Proof Size summary in bytes: - // Measured: `266` - // Estimated: `3731` - // Minimum execution time: 14_696_000 picoseconds. - Weight::from_parts(15_106_000, 3731) + // Measured: `300` + // Estimated: `3765` + // Minimum execution time: 17_208_000 picoseconds. + Weight::from_parts(18_307_000, 3765) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1606,10 +1757,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: `304` - // Estimated: `3769` - // Minimum execution time: 10_292_000 picoseconds. - Weight::from_parts(10_670_000, 3769) + // Measured: `338` + // Estimated: `3803` + // Minimum execution time: 13_686_000 picoseconds. + Weight::from_parts(14_186_000, 3803) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1617,10 +1768,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: `304` + // Measured: `338` // Estimated: `3561` - // Minimum execution time: 9_056_000 picoseconds. - Weight::from_parts(9_350_000, 3561) + // Minimum execution time: 12_381_000 picoseconds. + Weight::from_parts(13_208_000, 3561) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1629,9 +1780,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_145_000 picoseconds. - Weight::from_parts(10_744_073, 0) - // Standard Error: 72 - .saturating_add(Weight::from_parts(84_813, 0).saturating_mul(r.into())) + // Minimum execution time: 8_118_000 picoseconds. + Weight::from_parts(9_813_514, 0) + // Standard Error: 40 + .saturating_add(Weight::from_parts(71_154, 0).saturating_mul(r.into())) } } diff --git a/substrate/frame/revive/uapi/Cargo.toml b/substrate/frame/revive/uapi/Cargo.toml index 52de77a10944..0c7461a35d69 100644 --- a/substrate/frame/revive/uapi/Cargo.toml +++ b/substrate/frame/revive/uapi/Cargo.toml @@ -21,7 +21,7 @@ codec = { features = [ ], optional = true, workspace = true } [target.'cfg(target_arch = "riscv32")'.dependencies] -polkavm-derive = { version = "0.11.0" } +polkavm-derive = { version = "0.14.0" } [package.metadata.docs.rs] default-target = ["wasm32-unknown-unknown"] diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 2106b8fb49b7..6b3a8b07f040 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -105,6 +105,14 @@ pub trait HostFn: private::Sealed { /// - `output`: A reference to the output data buffer to write the block number. 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. + fn block_hash(block_number: &[u8; 32], output: &mut [u8; 32]); + /// Call (possibly transferring some amount of funds) into the specified account. /// /// # Parameters @@ -206,6 +214,17 @@ pub trait HostFn: private::Sealed { /// - `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 @@ -245,10 +264,24 @@ pub trait HostFn: private::Sealed { /// - `addr`: The address of the contract. /// - `output`: A reference to the output data buffer to write the code hash. /// - /// # Errors + /// # Note /// - /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] - fn code_hash(addr: &[u8; 20], output: &mut [u8; 32]) -> Result; + /// 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. /// @@ -290,7 +323,13 @@ pub trait HostFn: private::Sealed { /// # Parameters /// /// - `flags`: See [`CallFlags`] for a documentation of the supported flags. - /// - `code_hash`: The hash of the code to be executed. + /// - `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. @@ -305,7 +344,10 @@ pub trait HostFn: private::Sealed { /// - [CodeNotFound][`crate::ReturnErrorCode::CodeNotFound] 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_data: &[u8], output: Option<&mut &mut [u8]>, ) -> Result; @@ -567,18 +609,6 @@ pub trait HostFn: private::Sealed { /// [KeyNotFound][`crate::ReturnErrorCode::KeyNotFound] 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 diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv32.rs index 866b0ee8dd17..e8b27057ed18 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv32.rs @@ -58,23 +58,17 @@ 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 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) -> 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 own_code_hash(out_ptr: *mut u8); pub fn caller_is_origin() -> ReturnCode; pub fn caller_is_root() -> ReturnCode; @@ -96,6 +90,7 @@ mod sys { data_len: u32, ); 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); pub fn hash_keccak_256(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8); pub fn hash_blake2_256(input_ptr: *const u8, input_len: u32, out_ptr: *mut u8); @@ -304,24 +299,42 @@ impl HostFn for HostFnImpl { 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(packed)] + #[allow(dead_code)] + struct Args { + flags: u32, + address: *const u8, + ref_time_limit: u64, + proof_size_limit: u64, + deposit_limit: *const u8, + input: *const u8, + input_len: u32, + output: *mut u8, + output_len: *mut u32, + } + let args = Args { + flags: flags.bits(), + address: address.as_ptr(), + ref_time_limit, + proof_size_limit, + deposit_limit: deposit_limit_ptr, + input: input.as_ptr(), + input_len: input.len() as _, + output: output_ptr, + output_len: &mut output_len as *mut _, }; + 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); } @@ -329,11 +342,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( @@ -453,7 +461,7 @@ impl HostFn for HostFnImpl { impl_wrapper_for! { [u8; 32] => block_number, balance, value_transferred, now, minimum_balance, chain_id; - [u8; 20] => address, caller; + [u8; 20] => address, caller, origin; } fn weight_left(output: &mut &mut [u8]) { @@ -528,9 +536,12 @@ impl HostFn for HostFnImpl { ret_val.into() } - fn code_hash(address: &[u8; 20], output: &mut [u8; 32]) -> Result { - let ret_val = unsafe { sys::code_hash(address.as_ptr(), output.as_mut_ptr()) }; - ret_val.into() + 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], output: &mut [u8; 32]) { + unsafe { sys::code_size(address.as_ptr(), output.as_mut_ptr()) } } fn own_code_hash(output: &mut [u8; 32]) { @@ -574,4 +585,8 @@ impl HostFn for HostFnImpl { } 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/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-offences/src/tests.rs b/substrate/frame/root-offences/src/tests.rs index f96884d750da..289bb708efbb 100644 --- a/substrate/frame/root-offences/src/tests.rs +++ b/substrate/frame/root-offences/src/tests.rs @@ -17,7 +17,8 @@ use super::*; use frame_support::{assert_err, assert_ok}; -use mock::{active_era, start_session, Balances, ExtBuilder, RootOffences, RuntimeOrigin, System}; +use mock::{active_era, start_session, ExtBuilder, RootOffences, RuntimeOrigin, System, Test as T}; +use pallet_staking::asset; #[test] fn create_offence_fails_given_signed_origin() { @@ -35,18 +36,18 @@ fn create_offence_works_given_root_origin() { assert_eq!(active_era(), 0); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::staked::(&11), 1000); let offenders = [(11, Perbill::from_percent(50))].to_vec(); assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); System::assert_last_event(Event::OffenceCreated { offenders }.into()); // the slash should be applied right away. - assert_eq!(Balances::free_balance(11), 500); + assert_eq!(asset::staked::(&11), 500); // the other validator should keep their balance, because we only created // an offences for the first validator. - assert_eq!(Balances::free_balance(21), 1000); + assert_eq!(asset::staked::(&21), 1000); }) } @@ -58,7 +59,7 @@ fn create_offence_wont_slash_non_active_validators() { assert_eq!(active_era(), 0); // 31 is not an active validator. - assert_eq!(Balances::free_balance(31), 500); + assert_eq!(asset::staked::(&31), 500); let offenders = [(31, Perbill::from_percent(20)), (11, Perbill::from_percent(20))].to_vec(); assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); @@ -66,10 +67,10 @@ fn create_offence_wont_slash_non_active_validators() { System::assert_last_event(Event::OffenceCreated { offenders }.into()); // so 31 didn't get slashed. - assert_eq!(Balances::free_balance(31), 500); + assert_eq!(asset::staked::(&31), 500); // but 11 is an active validator so they got slashed. - assert_eq!(Balances::free_balance(11), 800); + assert_eq!(asset::staked::(&11), 800); }) } @@ -81,7 +82,7 @@ fn create_offence_wont_slash_idle() { assert_eq!(active_era(), 0); // 41 is idle. - assert_eq!(Balances::free_balance(41), 1000); + assert_eq!(asset::staked::(&41), 1000); let offenders = [(41, Perbill::from_percent(50))].to_vec(); assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); @@ -89,6 +90,6 @@ fn create_offence_wont_slash_idle() { System::assert_last_event(Event::OffenceCreated { offenders }.into()); // 41 didn't get slashed. - assert_eq!(Balances::free_balance(41), 1000); + assert_eq!(asset::staked::(&41), 1000); }) } 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/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/src/lib.rs b/substrate/frame/sassafras/src/lib.rs index 285758afbe6d..f6c409833e33 100644 --- a/substrate/frame/sassafras/src/lib.rs +++ b/substrate/frame/sassafras/src/lib.rs @@ -61,7 +61,7 @@ use frame_support::{ BoundedVec, WeakBoundedVec, }; use frame_system::{ - offchain::{SendTransactionTypes, SubmitTransaction}, + offchain::{CreateInherent, SubmitTransaction}, pallet_prelude::BlockNumberFor, }; use sp_consensus_sassafras::{ @@ -131,7 +131,7 @@ pub mod pallet { /// Configuration parameters. #[pallet::config] - pub trait Config: frame_system::Config + SendTransactionTypes> { + pub trait Config: frame_system::Config + CreateInherent> { /// Amount of slots that each epoch should last. #[pallet::constant] type EpochLength: Get; @@ -1020,7 +1020,8 @@ impl Pallet { pub fn submit_tickets_unsigned_extrinsic(tickets: Vec) -> bool { let tickets = BoundedVec::truncate_from(tickets); let call = Call::submit_tickets { tickets }; - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { + let xt = T::create_inherent(call.into()); + match SubmitTransaction::>::submit_transaction(xt) { Ok(_) => true, Err(e) => { error!(target: LOG_TARGET, "Error submitting tickets {:?}", e); diff --git a/substrate/frame/sassafras/src/mock.rs b/substrate/frame/sassafras/src/mock.rs index f145bffa3a05..d7e2fb63dc2f 100644 --- a/substrate/frame/sassafras/src/mock.rs +++ b/substrate/frame/sassafras/src/mock.rs @@ -34,7 +34,7 @@ use sp_core::{ H256, U256, }; use sp_runtime::{ - testing::{Digest, DigestItem, Header, TestXt}, + testing::{Digest, DigestItem, Header}, BuildStorage, }; @@ -48,12 +48,21 @@ impl frame_system::Config for Test { type Block = frame_system::mocking::MockBlock; } -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; - type Extrinsic = TestXt; + type RuntimeCall = RuntimeCall; + type Extrinsic = frame_system::mocking::MockUncheckedExtrinsic; +} + +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + frame_system::mocking::MockUncheckedExtrinsic::::new_bare(call) + } } impl pallet_sassafras::Config for Test { @@ -89,7 +98,7 @@ pub fn new_test_ext_with_pairs( with_ring_context: bool, ) -> (Vec, sp_io::TestExternalities) { let pairs = (0..authorities_len) - .map(|i| AuthorityPair::from_seed(&U256::from(i).into())) + .map(|i| AuthorityPair::from_seed(&U256::from(i).to_big_endian())) .collect::>(); let authorities: Vec<_> = pairs.iter().map(|p| p.public()).collect(); diff --git a/substrate/frame/scheduler/src/lib.rs b/substrate/frame/scheduler/src/lib.rs index 3eecf6d6f9e8..468099010bf9 100644 --- a/substrate/frame/scheduler/src/lib.rs +++ b/substrate/frame/scheduler/src/lib.rs @@ -1364,7 +1364,7 @@ impl Pallet { Some(&RawOrigin::Signed(_)) => T::WeightInfo::execute_dispatch_signed(), _ => T::WeightInfo::execute_dispatch_unsigned(), }; - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; // We only allow a scheduled call if it cannot push the weight past the limit. let max_weight = base_weight.saturating_add(call_weight); 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/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/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 e5fb15cdd07c..0ca36ca8545a 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -32,10 +32,17 @@ //! //! ## Usage //! -//! The main intended use of this crate is for it to be imported with its preludes: +//! This crate is organized into 3 stages: +//! +//! 1. preludes: `prelude`, `testing_prelude` and `runtime::prelude`, `benchmarking`, +//! `weights_prelude`, `try_runtime`. +//! 2. domain-specific modules: `traits`, `hashing`, `arithmetic` and `derive`. +//! 3. Accessing frame/substrate dependencies directly: `deps`. +//! +//! The main intended use of this crate is for it to be used with the former, preludes: //! //! ``` -//! # use polkadot_sdk_frame as frame; +//! use polkadot_sdk_frame as frame; //! #[frame::pallet] //! pub mod pallet { //! # use polkadot_sdk_frame as frame; @@ -49,36 +56,98 @@ //! pub struct Pallet(_); //! } //! +//! #[cfg(test)] //! pub mod tests { //! # use polkadot_sdk_frame as frame; //! use frame::testing_prelude::*; //! } //! +//! #[cfg(feature = "runtime-benchmarks")] +//! pub mod benchmarking { +//! # use polkadot_sdk_frame as frame; +//! use frame::benchmarking::prelude::*; +//! } +//! //! pub mod runtime { //! # use polkadot_sdk_frame as frame; //! use frame::runtime::prelude::*; //! } //! ``` //! -//! See: [`prelude`], [`testing_prelude`] and [`runtime::prelude`]. +//! If not in preludes, one can look into the domain-specific modules. Finally, if an import is +//! still not feasible, one can look into `deps`. //! -//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. +//! This crate also uses a `runtime` feature to include all of the types and tools needed to build +//! FRAME-based runtimes. So, if you want to build a runtime with this, import it as //! -//! ## Documentation +//! ```text +//! polkadot-sdk-frame = { version = "foo", features = ["runtime"] } +//! ``` //! -//! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html). +//! If you just want to build a pallet instead, import it as //! -//! ## Underlying dependencies +//! ```text +//! polkadot-sdk-frame = { version = "foo" } +//! ``` //! -//! This crate is an amalgamation of multiple other crates that are often used together to compose a -//! pallet. It is not necessary to use it, and it may fall short for certain purposes. +//! Notice that the preludes overlap since they have imports in common. More in detail: +//! - `testing_prelude` brings in frame `prelude` and `runtime::prelude`; +//! - `runtime::prelude` brings in frame `prelude`; +//! - `benchmarking` brings in frame `prelude`. +//! +//! ## Naming +//! +//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. This is due +//! to compatibility matters with `frame-support`. +//! +//! A typical pallet's `Cargo.toml` using this crate looks like: +//! +//! ```ignore +//! [dependencies] +//! codec = { features = ["max-encoded-len"], workspace = true } +//! scale-info = { features = ["derive"], workspace = true } +//! frame = { workspace = true, features = ["experimental", "runtime"] } +//! +//! [features] +//! default = ["std"] +//! std = [ +//! "codec/std", +//! "scale-info/std", +//! "frame/std", +//! ] +//! runtime-benchmarks = [ +//! "frame/runtime-benchmarks", +//! ] +//! try-runtime = [ +//! "frame/try-runtime", +//! ] +//! ``` +//! +//! ## Documentation //! -//! In short, this crate only re-exports types and traits from multiple sources. All of these -//! sources are listed (and re-exported again) in [`deps`]. +//! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html). //! //! ## WARNING: Experimental //! //! **This crate and all of its content is experimental, and should not yet be used in production.** +//! +//! ## Maintenance Note +//! +//! > Notes for the maintainers of this crate, describing how the re-exports and preludes should +//! > work. +//! +//! * Preludes should be extensive. The goal of this pallet is to be ONLY used with the preludes. +//! The domain-specific modules are just a backup, aiming to keep things organized. Don't hesitate +//! in adding more items to the main prelude. +//! * The only non-module, non-prelude items exported from the top level crate is the `pallet` +//! macro, such that we can have the `#[frame::pallet] mod pallet { .. }` syntax working. +//! * In most cases, you might want to create a domain-specific module, but also add it to the +//! preludes, such as `hashing`. +//! * The only items that should NOT be in preludes are those that have been placed in +//! `frame-support`/`sp-runtime`, but in truth are related to just one pallet. +//! * The currency related traits are kept out of the preludes to encourage a deliberate choice of +//! one over the other. +//! * `runtime::apis` should expose all common runtime APIs that all FRAME-based runtimes need. #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "experimental")] @@ -92,6 +161,9 @@ pub use frame_support::pallet_macros::{import_section, pallet_section}; /// The logging library of the runtime. Can normally be the classic `log` crate. pub use log; +#[doc(inline)] +pub use frame_support::storage_alias; + /// Macros used within the main [`pallet`] macro. /// /// Note: All of these macros are "stubs" and not really usable outside `#[pallet] mod pallet { .. @@ -128,6 +200,11 @@ pub mod prelude { #[doc(no_inline)] pub use frame_support::pallet_prelude::*; + /// Dispatch types from `frame-support`, other fundamental traits + #[doc(no_inline)] + pub use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; + pub use frame_support::traits::{Contains, IsSubType, OnRuntimeUpgrade}; + /// Pallet prelude of `frame-system`. #[doc(no_inline)] pub use frame_system::pallet_prelude::*; @@ -135,6 +212,78 @@ pub mod prelude { /// All FRAME-relevant derive macros. #[doc(no_inline)] pub use super::derive::*; + + /// All hashing related things + pub use super::hashing::*; + + /// Runtime traits + #[doc(no_inline)] + pub use sp_runtime::traits::{ + Bounded, DispatchInfoOf, Dispatchable, SaturatedConversion, Saturating, StaticLookup, + TrailingZeroInput, + }; + + /// Other error/result types for runtime + #[doc(no_inline)] + pub use sp_runtime::{DispatchErrorWithPostInfo, DispatchResultWithInfo, TokenError}; +} + +#[cfg(any(feature = "try-runtime", test))] +pub mod try_runtime { + pub use sp_runtime::TryRuntimeError; +} + +/// Prelude to be included in the `benchmarking.rs` of a pallet. +/// +/// It supports both the `benchmarking::v1::benchmarks` and `benchmarking::v2::benchmark` syntax. +/// +/// ``` +/// use polkadot_sdk_frame::benchmarking::prelude::*; +/// // rest of your code. +/// ``` +/// +/// It already includes `polkadot_sdk_frame::prelude::*` and `polkadot_sdk_frame::testing_prelude`. +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking { + mod shared { + pub use frame_benchmarking::{add_benchmark, v1::account, whitelist, whitelisted_caller}; + // all benchmarking functions. + pub use frame_benchmarking::benchmarking::*; + // The system origin, which is very often needed in benchmarking code. Might be tricky only + // if the pallet defines its own `#[pallet::origin]` and call it `RawOrigin`. + pub use frame_system::RawOrigin; + } + + #[deprecated( + note = "'The V1 benchmarking syntax is deprecated. Please use the V2 syntax. This warning may become a hard error any time after April 2025. For more info, see: https://github.com/paritytech/polkadot-sdk/pull/5995" + )] + pub mod v1 { + pub use super::shared::*; + pub use frame_benchmarking::benchmarks; + } + + pub mod prelude { + pub use super::shared::*; + pub use crate::prelude::*; + pub use frame_benchmarking::v2::*; + } +} + +/// Prelude to be included in the `weight.rs` of each pallet. +/// +/// ``` +/// pub use polkadot_sdk_frame::weights_prelude::*; +/// ``` +pub mod weights_prelude { + pub use core::marker::PhantomData; + pub use frame_support::{ + traits::Get, + weights::{ + constants::{ParityDbWeight, RocksDbWeight}, + Weight, + }, + }; + pub use frame_system; } /// The main testing prelude of FRAME. @@ -145,9 +294,13 @@ pub mod prelude { /// use polkadot_sdk_frame::testing_prelude::*; /// // rest of your test setup. /// ``` +/// +/// This automatically brings in `polkadot_sdk_frame::prelude::*` and +/// `polkadot_sdk_frame::runtime::prelude::*`. #[cfg(feature = "std")] pub mod testing_prelude { - pub use super::prelude::*; + pub use crate::{prelude::*, runtime::prelude::*}; + /// Testing includes building a runtime, so we bring in all preludes related to runtimes as /// well. pub use super::runtime::testing_prelude::*; @@ -159,6 +312,10 @@ pub mod testing_prelude { }; pub use frame_system::{self, mocking::*}; + + #[deprecated(note = "Use `frame::testing_prelude::TestExternalities` instead.")] + pub use sp_io::TestExternalities; + pub use sp_io::TestExternalities as TestState; } @@ -170,9 +327,13 @@ pub mod runtime { /// A runtime typically starts with: /// /// ``` - /// use polkadot_sdk_frame::{prelude::*, runtime::prelude::*}; + /// use polkadot_sdk_frame::runtime::prelude::*; /// ``` + /// + /// This automatically brings in `polkadot_sdk_frame::prelude::*`. pub mod prelude { + pub use crate::prelude::*; + /// All of the types related to the FRAME runtime executive. pub use frame_executive::*; @@ -212,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; @@ -222,7 +386,12 @@ pub mod runtime { // Types often used in the runtime APIs. pub use sp_core::OpaqueMetadata; + pub use sp_genesis_builder::{ + PresetId, Result as GenesisBuilderResult, DEV_RUNTIME_PRESET, + LOCAL_TESTNET_RUNTIME_PRESET, + }; pub use sp_inherents::{CheckInherentsResult, InherentData}; + pub use sp_keyring::AccountKeyring; pub use sp_runtime::{ApplyExtrinsicResult, ExtrinsicInclusionMode}; } @@ -246,6 +415,7 @@ pub mod runtime { pub use sp_block_builder::*; pub use sp_consensus_aura::*; pub use sp_consensus_grandpa::*; + pub use sp_genesis_builder::*; pub use sp_offchain::*; pub use sp_session::runtime_api::*; pub use sp_transaction_pool::runtime_api::*; @@ -291,8 +461,8 @@ pub mod runtime { /// The block type, which should be fed into [`frame_system::Config`]. /// - /// Should be parameterized with `T: frame_system::Config` and a tuple of `SignedExtension`. - /// When in doubt, use [`SystemSignedExtensionsOf`]. + /// Should be parameterized with `T: frame_system::Config` and a tuple of + /// `TransactionExtension`. When in doubt, use [`SystemTransactionExtensionsOf`]. // Note that this cannot be dependent on `T` for block-number because it would lead to a // circular dependency (self-referential generics). pub type BlockOf = generic::Block>; @@ -306,7 +476,7 @@ pub mod runtime { /// Default set of signed extensions exposed from the `frame_system`. /// /// crucially, this does NOT contain any tx-payment extension. - pub type SystemSignedExtensionsOf = ( + pub type SystemTransactionExtensionsOf = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -322,7 +492,6 @@ pub mod runtime { /// counter part of `runtime::prelude`. #[cfg(feature = "std")] pub mod testing_prelude { - pub use super::prelude::*; pub use sp_core::storage::Storage; pub use sp_runtime::BuildStorage; } @@ -344,12 +513,6 @@ pub mod arithmetic { pub use sp_arithmetic::{traits::*, *}; } -/// Low level primitive types used in FRAME pallets. -pub mod primitives { - pub use sp_core::{H160, H256, H512, U256, U512}; - pub use sp_runtime::traits::{BlakeTwo256, Hash, Keccak256}; -} - /// All derive macros used in frame. /// /// This is already part of the [`prelude`]. @@ -364,12 +527,17 @@ pub mod derive { pub use sp_runtime::RuntimeDebug; } -/// Access to all of the dependencies of this crate. In case the re-exports are not enough, this -/// module can be used. +pub mod hashing { + pub use sp_core::{hashing::*, H160, H256, H512, U256, U512}; + pub use sp_runtime::traits::{BlakeTwo256, Hash, Keccak256}; +} + +/// Access to all of the dependencies of this crate. In case the prelude re-exports are not enough, +/// this module can be used. /// -/// Any time one uses this module to access a dependency, you can have a moment to think about -/// whether this item could have been placed in any of the other modules and preludes in this crate. -/// In most cases, hopefully the answer is yes. +/// Note for maintainers: Any time one uses this module to access a dependency, you can have a +/// moment to think about whether this item could have been placed in any of the other modules and +/// preludes in this crate. In most cases, hopefully the answer is yes. pub mod deps { // TODO: It would be great to somehow instruct RA to prefer *not* suggesting auto-imports from // these. For example, we prefer `polkadot_sdk_frame::derive::CloneNoBound` rather than @@ -396,8 +564,12 @@ pub mod deps { #[cfg(feature = "runtime")] pub use sp_consensus_grandpa; #[cfg(feature = "runtime")] + pub use sp_genesis_builder; + #[cfg(feature = "runtime")] pub use sp_inherents; #[cfg(feature = "runtime")] + pub use sp_keyring; + #[cfg(feature = "runtime")] pub use sp_offchain; #[cfg(feature = "runtime")] pub use sp_storage; 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/src/asset.rs b/substrate/frame/staking/src/asset.rs new file mode 100644 index 000000000000..23368b1f8fca --- /dev/null +++ b/substrate/frame/staking/src/asset.rs @@ -0,0 +1,125 @@ +// 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. + +//! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking +//! asset. + +use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency}; + +use crate::{BalanceOf, Config, NegativeImbalanceOf, PositiveImbalanceOf}; + +/// Existential deposit for the chain. +pub fn existential_deposit() -> BalanceOf { + T::Currency::minimum_balance() +} + +/// Total issuance of the chain. +pub fn total_issuance() -> BalanceOf { + T::Currency::total_issuance() +} + +/// Total balance of `who`. Includes both, free and reserved. +pub fn total_balance(who: &T::AccountId) -> BalanceOf { + T::Currency::total_balance(who) +} + +/// Stakeable balance of `who`. +/// +/// This includes balance free to stake along with any balance that is already staked. +pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { + T::Currency::free_balance(who) +} + +/// Balance of `who` that is currently at stake. +/// +/// The staked amount is locked and cannot be transferred out of `who`s account. +pub fn staked(who: &T::AccountId) -> BalanceOf { + T::Currency::balance_locked(crate::STAKING_ID, who) +} + +/// Set balance that can be staked for `who`. +/// +/// This includes any balance that is already staked. +#[cfg(any(test, feature = "runtime-benchmarks"))] +pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { + T::Currency::make_free_balance_be(who, value); +} + +/// Update `amount` at stake for `who`. +/// +/// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the +/// difference is unlocked. +pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { + T::Currency::set_lock( + crate::STAKING_ID, + who, + amount, + frame_support::traits::WithdrawReasons::all(), + ); +} + +/// Kill the stake of `who`. +/// +/// All locked amount is unlocked. +pub fn kill_stake(who: &T::AccountId) { + T::Currency::remove_lock(crate::STAKING_ID, who); +} + +/// Slash the value from `who`. +/// +/// A negative imbalance is returned which can be resolved to deposit the slashed value. +pub fn slash( + who: &T::AccountId, + value: BalanceOf, +) -> (NegativeImbalanceOf, BalanceOf) { + T::Currency::slash(who, value) +} + +/// Mint `value` into an existing account `who`. +/// +/// This does not increase the total issuance. +pub fn mint_existing( + who: &T::AccountId, + value: BalanceOf, +) -> Option> { + T::Currency::deposit_into_existing(who, value).ok() +} + +/// Mint reward and create account for `who` if it does not exist. +/// +/// This does not increase the total issuance. +pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { + T::Currency::deposit_creating(who, value) +} + +/// Deposit newly issued or slashed `value` into `who`. +pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf) { + T::Currency::resolve_creating(who, value) +} + +/// Issue `value` increasing total issuance. +/// +/// Creates a negative imbalance. +pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { + T::Currency::issue(value) +} + +/// Burn the amount from the total issuance. +#[cfg(feature = "runtime-benchmarks")] +pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { + T::Currency::burn(amount) +} diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 1f8580d7a3e6..79d8dd3fbc30 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Staking pallet benchmarking. use super::*; -use crate::{ConfigOp, Pallet as Staking}; +use crate::{asset, ConfigOp, Pallet as Staking}; use testing_utils::*; use codec::Decode; @@ -26,7 +26,7 @@ use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProv use frame_support::{ pallet_prelude::*, storage::bounded_vec::BoundedVec, - traits::{Currency, Get, Imbalance, UnfilteredDispatchable}, + traits::{Get, Imbalance, UnfilteredDispatchable}, }; use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, @@ -34,8 +34,8 @@ use sp_runtime::{ }; use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex}; -pub use frame_benchmarking::v1::{ - account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, +pub use frame_benchmarking::{ + impl_benchmark_test_suite, v2::*, whitelist_account, whitelisted_caller, BenchmarkError, }; use frame_system::RawOrigin; @@ -132,7 +132,7 @@ pub fn create_validator_with_nominators( ErasRewardPoints::::insert(current_era, reward); // Create reward pool - let total_payout = T::Currency::minimum_balance() + let total_payout = asset::existential_deposit::() .saturating_mul(upper_bound.into()) .saturating_mul(1000u32.into()); >::insert(current_era, total_payout); @@ -167,7 +167,7 @@ impl ListScenario { ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); // burn the entire issuance. - let i = T::Currency::burn(T::Currency::total_issuance()); + let i = asset::burn::(asset::total_issuance::()); core::mem::forget(i); // create accounts with the origin weight @@ -197,7 +197,7 @@ impl ListScenario { let dest_weight_as_vote = T::VoterList::score_update_worst_case(&origin_stash1, is_increase); - let total_issuance = T::Currency::total_issuance(); + let total_issuance = asset::total_issuance::(); let dest_weight = T::CurrencyToVote::to_currency(dest_weight_as_vote as u128, total_issuance); @@ -219,23 +219,30 @@ impl ListScenario { const USER_SEED: u32 = 999666; -benchmarks! { - bond { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn bond() { let stash = create_funded_user::("stash", USER_SEED, 100); let reward_destination = RewardDestination::Staked; - let amount = T::Currency::minimum_balance() * 10u32.into(); + let amount = asset::existential_deposit::() * 10u32.into(); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash.clone()), amount, reward_destination) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash.clone()), amount, reward_destination); + assert!(Bonded::::contains_key(stash.clone())); assert!(Ledger::::contains_key(stash)); } - bond_extra { + #[benchmark] + fn bond_extra() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup the worst case list scenario. @@ -246,25 +253,29 @@ benchmarks! { let stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1; - let original_bonded: BalanceOf - = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; + let original_bonded: BalanceOf = Ledger::::get(&controller) + .map(|l| l.active) + .ok_or("ledger not created after")?; - let _ = T::Currency::deposit_into_existing(&stash, max_additional).unwrap(); + let _ = asset::mint_existing::(&stash, max_additional).unwrap(); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash), max_additional) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash), max_additional); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; assert!(original_bonded < new_bonded); + + Ok(()) } - unbond { + #[benchmark] + fn unbond() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - // setup the worst case list scenario. - let total_issuance = T::Currency::total_issuance(); // 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 = BalanceOf::::try_from(952_994_955_240_703u128) @@ -272,47 +283,58 @@ benchmarks! { .unwrap(); let scenario = ListScenario::::new(origin_weight, false)?; - let stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1.clone(); let amount = origin_weight - scenario.dest_weight; let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; let original_bonded: BalanceOf = ledger.active; whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), amount) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), amount); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; assert!(original_bonded > new_bonded); + + Ok(()) } + #[benchmark] // Withdraw only updates the ledger - withdraw_unbonded_update { + fn withdraw_unbonded_update( // Slashing Spans - let s in 0 .. MAX_SPANS; + s: Linear<0, MAX_SPANS>, + ) -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; add_slashing_spans::(&stash, s); - let amount = T::Currency::minimum_balance() * 5u32.into(); // Half of total + let amount = asset::existential_deposit::() * 5u32.into(); // Half of total Staking::::unbond(RawOrigin::Signed(controller.clone()).into(), amount)?; CurrentEra::::put(EraIndex::max_value()); let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; let original_total: BalanceOf = ledger.total; whitelist_account!(controller); - }: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s) - verify { + + #[extrinsic_call] + withdraw_unbonded(RawOrigin::Signed(controller.clone()), s); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_total: BalanceOf = ledger.total; assert!(original_total > new_total); + + Ok(()) } + #[benchmark] // Worst case scenario, everything is removed after the bonding duration - withdraw_unbonded_kill { + fn withdraw_unbonded_kill( // Slashing Spans - let s in 0 .. MAX_SPANS; + s: Linear<0, MAX_SPANS>, + ) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -322,20 +344,25 @@ benchmarks! { add_slashing_spans::(&stash, s); assert!(T::VoterList::contains(&stash)); - let ed = T::Currency::minimum_balance(); + let ed = asset::existential_deposit::(); let mut ledger = Ledger::::get(&controller).unwrap(); ledger.active = ed - One::one(); Ledger::::insert(&controller, ledger); CurrentEra::::put(EraIndex::max_value()); whitelist_account!(controller); - }: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s) - verify { + + #[extrinsic_call] + withdraw_unbonded(RawOrigin::Signed(controller.clone()), s); + assert!(!Ledger::::contains_key(controller)); assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - validate { + #[benchmark] + fn validate() -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::( MaxNominationsOf::::get() - 1, 100, @@ -346,22 +373,28 @@ benchmarks! { let prefs = ValidatorPrefs::default(); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), prefs) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), prefs); + assert!(Validators::::contains_key(&stash)); assert!(T::VoterList::contains(&stash)); + + Ok(()) } - kick { + #[benchmark] + fn kick( // scenario: we want to kick `k` nominators from nominating us (we are a validator). // we'll assume that `k` is under 128 for the purposes of determining the slope. - // each nominator should have `T::MaxNominations::get()` validators nominated, and our validator - // should be somewhere in there. - let k in 1 .. 128; - + // each nominator should have `T::MaxNominations::get()` validators nominated, and our + // validator should be somewhere in there. + k: Linear<1, 128>, + ) -> Result<(), BenchmarkError> { // these are the other validators; there are `T::MaxNominations::get() - 1` of them, so // there are a total of `T::MaxNominations::get()` validators in the system. - let rest_of_validators = create_validators_with_seed::(MaxNominationsOf::::get() - 1, 100, 415)?; + let rest_of_validators = + create_validators_with_seed::(MaxNominationsOf::::get() - 1, 100, 415)?; // this is the validator that will be kicking. let (stash, controller) = create_stash_controller::( @@ -377,7 +410,7 @@ benchmarks! { // we now create the nominators. there will be `k` of them; each will nominate all // validators. we will then kick each of the `k` nominators from the main validator. let mut nominator_stashes = Vec::with_capacity(k as usize); - for i in 0 .. k { + for i in 0..k { // create a nominator stash. let (n_stash, n_controller) = create_stash_controller::( MaxNominationsOf::::get() + i, @@ -402,53 +435,64 @@ benchmarks! { } // we need the unlookuped version of the nominator stash for the kick. - let kicks = nominator_stashes.iter() + let kicks = nominator_stashes + .iter() .map(|n| T::Lookup::unlookup(n.clone())) .collect::>(); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), kicks) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), kicks); + // all nominators now should *not* be nominating our validator... for n in nominator_stashes.iter() { assert!(!Nominators::::get(n).unwrap().targets.contains(&stash)); } + + Ok(()) } + #[benchmark] // Worst case scenario, T::MaxNominations::get() - nominate { - let n in 1 .. MaxNominationsOf::::get(); - + fn nominate(n: Linear<1, { MaxNominationsOf::::get() }>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); - // setup a worst case list scenario. Note we don't care about the destination position, because - // we are just doing an insert into the origin position. - let scenario = ListScenario::::new(origin_weight, true)?; + // setup a worst case list scenario. Note we don't care about the destination position, + // because we are just doing an insert into the origin position. + ListScenario::::new(origin_weight, true)?; let (stash, controller) = create_stash_controller_with_balance::( - SEED + MaxNominationsOf::::get() + 1, // make sure the account does not conflict with others + SEED + MaxNominationsOf::::get() + 1, /* make sure the account does not conflict + * with others */ origin_weight, RewardDestination::Staked, - ).unwrap(); + ) + .unwrap(); assert!(!Nominators::::contains_key(&stash)); assert!(!T::VoterList::contains(&stash)); let validators = create_validators::(n, 100).unwrap(); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), validators) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), validators); + assert!(Nominators::::contains_key(&stash)); - assert!(T::VoterList::contains(&stash)) + assert!(T::VoterList::contains(&stash)); + + Ok(()) } - chill { + #[benchmark] + fn chill() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -458,97 +502,138 @@ benchmarks! { assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller)) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller)); + assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - set_payee { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + #[benchmark] + fn set_payee() -> Result<(), BenchmarkError> { + let (stash, controller) = + create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; assert_eq!(Payee::::get(&stash), Some(RewardDestination::Staked)); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone())); + assert_eq!(Payee::::get(&stash), Some(RewardDestination::Account(controller))); + + Ok(()) } - update_payee { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + #[benchmark] + fn update_payee() -> Result<(), BenchmarkError> { + let (stash, controller) = + create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; Payee::::insert(&stash, { #[allow(deprecated)] RewardDestination::Controller }); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), controller.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), controller.clone()); + assert_eq!(Payee::::get(&stash), Some(RewardDestination::Account(controller))); + + Ok(()) } - set_controller { - let (stash, ctlr) = create_unique_stash_controller::(9000, 100, RewardDestination::Staked, false)?; + #[benchmark] + fn set_controller() -> Result<(), BenchmarkError> { + let (stash, ctlr) = + create_unique_stash_controller::(9000, 100, RewardDestination::Staked, false)?; // ensure `ctlr` is the currently stored controller. assert!(!Ledger::::contains_key(&stash)); assert!(Ledger::::contains_key(&ctlr)); assert_eq!(Bonded::::get(&stash), Some(ctlr.clone())); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash.clone())); + assert!(Ledger::::contains_key(&stash)); + + Ok(()) } - set_validator_count { + #[benchmark] + fn set_validator_count() { let validator_count = MaxValidators::::get(); - }: _(RawOrigin::Root, validator_count) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, validator_count); + assert_eq!(ValidatorCount::::get(), validator_count); } - force_no_eras {}: _(RawOrigin::Root) - verify { assert_eq!(ForceEra::::get(), Forcing::ForceNone); } + #[benchmark] + fn force_no_eras() { + #[extrinsic_call] + _(RawOrigin::Root); - force_new_era {}: _(RawOrigin::Root) - verify { assert_eq!(ForceEra::::get(), Forcing::ForceNew); } + assert_eq!(ForceEra::::get(), Forcing::ForceNone); + } + + #[benchmark] + fn force_new_era() { + #[extrinsic_call] + _(RawOrigin::Root); - force_new_era_always {}: _(RawOrigin::Root) - verify { assert_eq!(ForceEra::::get(), Forcing::ForceAlways); } + assert_eq!(ForceEra::::get(), Forcing::ForceNew); + } + #[benchmark] + fn force_new_era_always() { + #[extrinsic_call] + _(RawOrigin::Root); + + assert_eq!(ForceEra::::get(), Forcing::ForceAlways); + } + + #[benchmark] // Worst case scenario, the list of invulnerables is very long. - set_invulnerables { - let v in 0 .. MaxValidators::::get(); + fn set_invulnerables(v: Linear<0, { MaxValidators::::get() }>) { let mut invulnerables = Vec::new(); - for i in 0 .. v { + for i in 0..v { invulnerables.push(account("invulnerable", i, SEED)); } - }: _(RawOrigin::Root, invulnerables) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, invulnerables); + assert_eq!(Invulnerables::::get().len(), v as usize); } - deprecate_controller_batch { + #[benchmark] + fn deprecate_controller_batch( // We pass a dynamic number of controllers to the benchmark, up to // `MaxControllersInDeprecationBatch`. - let i in 0 .. T::MaxControllersInDeprecationBatch::get(); - + u: Linear<0, { T::MaxControllersInDeprecationBatch::get() }>, + ) -> Result<(), BenchmarkError> { let mut controllers: Vec<_> = vec![]; let mut stashes: Vec<_> = vec![]; - for n in 0..i as u32 { - let (stash, controller) = create_unique_stash_controller::( - n, - 100, - RewardDestination::Staked, - false - )?; + for i in 0..u as u32 { + let (stash, controller) = + create_unique_stash_controller::(i, 100, RewardDestination::Staked, false)?; controllers.push(controller); stashes.push(stash); } let bounded_controllers: BoundedVec<_, T::MaxControllersInDeprecationBatch> = BoundedVec::try_from(controllers.clone()).unwrap(); - }: _(RawOrigin::Root, bounded_controllers) - verify { - for n in 0..i as u32 { - let stash = &stashes[n as usize]; - let controller = &controllers[n as usize]; + + #[extrinsic_call] + _(RawOrigin::Root, bounded_controllers); + + for i in 0..u as u32 { + let stash = &stashes[i as usize]; + let controller = &controllers[i as usize]; // Ledger no longer keyed by controller. assert_eq!(Ledger::::get(controller), None); // Bonded now maps to the stash. @@ -556,15 +641,19 @@ benchmarks! { // Ledger is now keyed by stash. assert_eq!(Ledger::::get(stash).unwrap().stash, *stash); } + + Ok(()) } - force_unstake { + #[benchmark] + fn force_unstake( // Slashing Spans - let s in 0 .. MAX_SPANS; + s: Linear<0, MAX_SPANS>, + ) -> Result<(), BenchmarkError> { // Clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -574,30 +663,38 @@ benchmarks! { assert!(T::VoterList::contains(&stash)); add_slashing_spans::(&stash, s); - }: _(RawOrigin::Root, stash.clone(), s) - verify { + #[extrinsic_call] + _(RawOrigin::Root, stash.clone(), s); + assert!(!Ledger::::contains_key(&controller)); assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - cancel_deferred_slash { - let s in 1 .. MAX_SLASHES; + #[benchmark] + fn cancel_deferred_slash(s: Linear<1, MAX_SLASHES>) { let mut unapplied_slashes = Vec::new(); let era = EraIndex::one(); let dummy = || T::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap(); - for _ in 0 .. MAX_SLASHES { - unapplied_slashes.push(UnappliedSlash::>::default_from(dummy())); + for _ in 0..MAX_SLASHES { + unapplied_slashes + .push(UnappliedSlash::>::default_from(dummy())); } UnappliedSlashes::::insert(era, &unapplied_slashes); - let slash_indices: Vec = (0 .. s).collect(); - }: _(RawOrigin::Root, era, slash_indices) - verify { + let slash_indices: Vec = (0..s).collect(); + + #[extrinsic_call] + _(RawOrigin::Root, era, slash_indices); + assert_eq!(UnappliedSlashes::::get(&era).len(), (MAX_SLASHES - s) as usize); } - payout_stakers_alive_staked { - let n in 0 .. T::MaxExposurePageSize::get() as u32; + #[benchmark] + fn payout_stakers_alive_staked( + n: Linear<0, { T::MaxExposurePageSize::get() as u32 }>, + ) -> Result<(), BenchmarkError> { let (validator, nominators) = create_validator_with_nominators::( n, T::MaxExposurePageSize::get() as u32, @@ -608,39 +705,47 @@ benchmarks! { let current_era = CurrentEra::::get().unwrap(); // set the commission for this particular era as well. - >::insert(current_era, validator.clone(), >::validators(&validator)); + >::insert( + current_era, + validator.clone(), + Validators::::get(&validator), + ); let caller = whitelisted_caller(); - let balance_before = T::Currency::free_balance(&validator); + let balance_before = asset::stakeable_balance::(&validator); let mut nominator_balances_before = Vec::new(); for (stash, _) in &nominators { - let balance = T::Currency::free_balance(stash); + let balance = asset::stakeable_balance::(stash); nominator_balances_before.push(balance); } - }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) - verify { - let balance_after = T::Currency::free_balance(&validator); + + #[extrinsic_call] + payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era); + + let balance_after = asset::stakeable_balance::(&validator); ensure!( balance_before < balance_after, "Balance of validator stash should have increased after payout.", ); - for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { - let balance_after = T::Currency::free_balance(stash); + for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) + { + let balance_after = asset::stakeable_balance::(stash); ensure!( balance_before < &balance_after, "Balance of nominator stash should have increased after payout.", ); } - } - rebond { - let l in 1 .. T::MaxUnlockingChunks::get() as u32; + Ok(()) + } + #[benchmark] + fn rebond(l: Linear<1, { T::MaxUnlockingChunks::get() as u32 }>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); let origin_weight = MinNominatorBond::::get() - .max(T::Currency::minimum_balance()) + .max(asset::existential_deposit::()) // we use 100 to play friendly with the list threshold values in the mock .max(100u32.into()); @@ -658,35 +763,35 @@ benchmarks! { // so the sum of unlocking chunks puts voter into the dest bag. assert!(value * l.into() + origin_weight > origin_weight); assert!(value * l.into() + origin_weight <= dest_weight); - let unlock_chunk = UnlockChunk::> { - value, - era: EraIndex::zero(), - }; + let unlock_chunk = UnlockChunk::> { value, era: EraIndex::zero() }; - let stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); - for _ in 0 .. l { + for _ in 0..l { staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap() } Ledger::::insert(controller.clone(), staking_ledger.clone()); let original_bonded: BalanceOf = staking_ledger.active; whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), rebond_amount) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), rebond_amount); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; assert!(original_bonded < new_bonded); + + Ok(()) } - reap_stash { - let s in 1 .. MAX_SPANS; + #[benchmark] + fn reap_stash(s: Linear<1, MAX_SPANS>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -695,26 +800,26 @@ benchmarks! { let stash = scenario.origin_stash1; add_slashing_spans::(&stash, s); - let l = StakingLedger::::new( - stash.clone(), - T::Currency::minimum_balance() - One::one(), - ); + let l = + StakingLedger::::new(stash.clone(), asset::existential_deposit::() - One::one()); Ledger::::insert(&controller, l); assert!(Bonded::::contains_key(&stash)); assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), stash.clone(), s) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), stash.clone(), s); + assert!(!Bonded::::contains_key(&stash)); assert!(!T::VoterList::contains(&stash)); - } - new_era { - let v in 1 .. 10; - let n in 0 .. 100; + Ok(()) + } + #[benchmark] + fn new_era(v: Linear<1, 10>, n: Linear<0, 100>) -> Result<(), BenchmarkError> { create_validators_with_nominators_for_era::( v, n, @@ -723,16 +828,21 @@ benchmarks! { None, )?; let session_index = SessionIndex::one(); - }: { - let validators = Staking::::try_trigger_new_era(session_index, true) - .ok_or("`new_era` failed")?; + + let validators; + #[block] + { + validators = + Staking::::try_trigger_new_era(session_index, true).ok_or("`new_era` failed")?; + } + assert!(validators.len() == v as usize); + + Ok(()) } - #[extra] - payout_all { - let v in 1 .. 10; - let n in 0 .. 100; + #[benchmark(extra)] + fn payout_all(v: Linear<1, 10>, n: Linear<0, 100>) -> Result<(), BenchmarkError> { create_validators_with_nominators_for_era::( v, n, @@ -764,99 +874,142 @@ benchmarks! { ErasRewardPoints::::insert(current_era, reward); // Create reward pool - let total_payout = T::Currency::minimum_balance() * 1000u32.into(); + let total_payout = asset::existential_deposit::() * 1000u32.into(); >::insert(current_era, total_payout); let caller: T::AccountId = whitelisted_caller(); let origin = RawOrigin::Signed(caller); - let calls: Vec<_> = payout_calls_arg.iter().map(|arg| - Call::::payout_stakers_by_page { validator_stash: arg.0.clone(), era: arg.1, page: 0 }.encode() - ).collect(); - }: { - for call in calls { - as Decode>::decode(&mut &*call) - .expect("call is encoded above, encoding must be correct") - .dispatch_bypass_filter(origin.clone().into())?; + let calls: Vec<_> = payout_calls_arg + .iter() + .map(|arg| { + Call::::payout_stakers_by_page { + validator_stash: arg.0.clone(), + era: arg.1, + page: 0, + } + .encode() + }) + .collect(); + + #[block] + { + for call in calls { + as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(origin.clone().into())?; + } } + + Ok(()) } - #[extra] - do_slash { - let l in 1 .. T::MaxUnlockingChunks::get() as u32; + #[benchmark(extra)] + fn do_slash( + l: Linear<1, { T::MaxUnlockingChunks::get() as u32 }>, + ) -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); - let unlock_chunk = UnlockChunk::> { - value: 1u32.into(), - era: EraIndex::zero(), - }; - for _ in 0 .. l { + let unlock_chunk = + UnlockChunk::> { value: 1u32.into(), era: EraIndex::zero() }; + for _ in 0..l { staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap(); } Ledger::::insert(controller, staking_ledger); - let slash_amount = T::Currency::minimum_balance() * 10u32.into(); - let balance_before = T::Currency::free_balance(&stash); - }: { - crate::slashing::do_slash::( - &stash, - slash_amount, - &mut BalanceOf::::zero(), - &mut NegativeImbalanceOf::::zero(), - EraIndex::zero() - ); - } verify { - let balance_after = T::Currency::free_balance(&stash); + let slash_amount = asset::existential_deposit::() * 10u32.into(); + let balance_before = asset::stakeable_balance::(&stash); + + #[block] + { + crate::slashing::do_slash::( + &stash, + slash_amount, + &mut BalanceOf::::zero(), + &mut NegativeImbalanceOf::::zero(), + EraIndex::zero(), + ); + } + + let balance_after = asset::stakeable_balance::(&stash); assert!(balance_before > balance_after); + + Ok(()) } - get_npos_voters { + #[benchmark] + fn get_npos_voters( // number of validator intention. we will iterate all of them. - let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); - // number of nominator intention. we will iterate all of them. - let n in (MaxNominators::::get() / 2) .. MaxNominators::::get(); + v: Linear<{ MaxValidators::::get() / 2 }, { MaxValidators::::get() }>, - let validators = create_validators_with_nominators_for_era::( - v, n, MaxNominationsOf::::get() as usize, false, None - )? - .into_iter() - .map(|v| T::Lookup::lookup(v).unwrap()) - .collect::>(); + // number of nominator intention. we will iterate all of them. + n: Linear<{ MaxNominators::::get() / 2 }, { MaxNominators::::get() }>, + ) -> Result<(), BenchmarkError> { + create_validators_with_nominators_for_era::( + v, + n, + MaxNominationsOf::::get() as usize, + false, + None, + )?; assert_eq!(Validators::::count(), v); assert_eq!(Nominators::::count(), n); let num_voters = (v + n) as usize; - }: { + // default bounds are unbounded. - let voters = >::get_npos_voters(DataProviderBounds::default()); + let voters; + #[block] + { + voters = >::get_npos_voters(DataProviderBounds::default()); + } + assert_eq!(voters.len(), num_voters); + + Ok(()) } - get_npos_targets { + #[benchmark] + fn get_npos_targets( // number of validator intention. - let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); + v: Linear<{ MaxValidators::::get() / 2 }, { MaxValidators::::get() }>, + ) -> Result<(), BenchmarkError> { // number of nominator intention. let n = MaxNominators::::get(); - - let _ = create_validators_with_nominators_for_era::( - v, n, MaxNominationsOf::::get() as usize, false, None + create_validators_with_nominators_for_era::( + v, + n, + MaxNominationsOf::::get() as usize, + false, + None, )?; - }: { - // default bounds are unbounded. - let targets = >::get_npos_targets(DataProviderBounds::default()); + + let targets; + + #[block] + { + // default bounds are unbounded. + targets = >::get_npos_targets(DataProviderBounds::default()); + } + assert_eq!(targets.len() as u32, v); + + Ok(()) } - set_staking_configs_all_set { - }: set_staking_configs( - RawOrigin::Root, - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(Percent::max_value()), - ConfigOp::Set(Perbill::max_value()), - ConfigOp::Set(Percent::max_value()) - ) verify { + #[benchmark] + fn set_staking_configs_all_set() { + #[extrinsic_call] + set_staking_configs( + RawOrigin::Root, + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(Percent::max_value()), + ConfigOp::Set(Perbill::max_value()), + ConfigOp::Set(Percent::max_value()), + ); + assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxNominatorsCount::::get(), Some(u32::MAX)); @@ -866,17 +1019,20 @@ benchmarks! { assert_eq!(MaxStakedRewards::::get(), Some(Percent::from_percent(100))); } - set_staking_configs_all_remove { - }: set_staking_configs( - RawOrigin::Root, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove - ) verify { + #[benchmark] + fn set_staking_configs_all_remove() { + #[extrinsic_call] + set_staking_configs( + RawOrigin::Root, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ); + assert!(!MinNominatorBond::::exists()); assert!(!MinValidatorBond::::exists()); assert!(!MaxNominatorsCount::::exists()); @@ -886,16 +1042,16 @@ benchmarks! { assert!(!MaxStakedRewards::::exists()); } - chill_other { + #[benchmark] + fn chill_other() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; - let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1; assert!(T::VoterList::contains(&stash)); @@ -911,18 +1067,22 @@ benchmarks! { )?; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), stash.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), stash.clone()); + assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - force_apply_min_commission { + #[benchmark] + fn force_apply_min_commission() -> Result<(), BenchmarkError> { // Clean up any existing state clear_validators_and_nominators::(); // Create a validator with a commission of 50% - let (stash, controller) = - create_stash_controller::(1, 1, RewardDestination::Staked)?; + let (stash, controller) = create_stash_controller::(1, 1, RewardDestination::Staked)?; let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; Staking::::validate(RawOrigin::Signed(controller).into(), validator_prefs)?; @@ -936,29 +1096,41 @@ benchmarks! { // Set the min commission to 75% MinCommission::::set(Perbill::from_percent(75)); let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), stash.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), stash.clone()); + // The validators commission has been bumped to 75% assert_eq!( Validators::::get(&stash), ValidatorPrefs { commission: Perbill::from_percent(75), ..Default::default() } ); + + Ok(()) } - set_min_commission { + #[benchmark] + fn set_min_commission() { let min_commission = Perbill::max_value(); - }: _(RawOrigin::Root, min_commission) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, min_commission); + assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } - restore_ledger { + #[benchmark] + fn restore_ledger() -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; // corrupt ledger. Ledger::::remove(controller); - }: _(RawOrigin::Root, stash.clone(), None, None, None) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, stash.clone(), None, None, None); + assert_eq!(Staking::::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok)); + + Ok(()) } impl_benchmark_test_suite!( @@ -972,7 +1144,7 @@ benchmarks! { #[cfg(test)] mod tests { use super::*; - use crate::mock::{Balances, ExtBuilder, RuntimeOrigin, Staking, Test}; + use crate::mock::{ExtBuilder, RuntimeOrigin, Staking, Test}; use frame_support::assert_ok; #[test] @@ -1019,16 +1191,17 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); - let original_free_balance = Balances::free_balance(&validator_stash); + let original_stakeable_balance = asset::stakeable_balance::(&validator_stash); assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), validator_stash, current_era, 0 )); - let new_free_balance = Balances::free_balance(&validator_stash); + let new_stakeable_balance = asset::stakeable_balance::(&validator_stash); - assert!(original_free_balance < new_free_balance); + // reward increases stakeable balance + assert!(original_stakeable_balance < new_stakeable_balance); }); } @@ -1064,25 +1237,4 @@ mod tests { } }); } - - #[test] - fn test_payout_all() { - ExtBuilder::default().build_and_execute(|| { - let v = 10; - let n = 100; - - let selected_benchmark = SelectedBenchmark::payout_all; - let c = vec![ - (frame_benchmarking::BenchmarkParameter::v, v), - (frame_benchmarking::BenchmarkParameter::n, n), - ]; - - assert_ok!( - >::unit_test_instance( - &selected_benchmark, - &c, - ) - ); - }); - } } diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index dc4b4fc326b8..ac3be04cf607 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -31,15 +31,12 @@ //! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure //! state consistency. -use frame_support::{ - defensive, ensure, - traits::{Defensive, LockableCurrency}, -}; +use frame_support::{defensive, ensure, traits::Defensive}; use sp_staking::{StakingAccount, StakingInterface}; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, - VirtualStakers, STAKING_ID, + asset, BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, + StakingLedger, VirtualStakers, }; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -190,12 +187,7 @@ impl StakingLedger { // We skip locking virtual stakers. if !Pallet::::is_virtual_staker(&self.stash) { // for direct stakers, update lock on stash based on ledger. - T::Currency::set_lock( - STAKING_ID, - &self.stash, - self.total, - frame_support::traits::WithdrawReasons::all(), - ); + asset::update_stake::(&self.stash, self.total); } Ledger::::insert( @@ -269,7 +261,7 @@ impl StakingLedger { // kill virtual staker if it exists. if >::take(&stash).is_none() { // if not virtual staker, clear locks. - T::Currency::remove_lock(STAKING_ID, &ledger.stash); + asset::kill_stake::(&ledger.stash); } Ok(()) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 9e59cbd3d0cb..6361663b2b1c 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -295,6 +295,7 @@ pub(crate) mod mock; #[cfg(test)] mod tests; +pub mod asset; pub mod election_size_tracker; pub mod inflation; pub mod ledger; @@ -323,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, }; @@ -848,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. @@ -872,6 +876,10 @@ where >::disable_index(validator_index) } + fn enable_validator(validator_index: u32) -> bool { + >::enable_index(validator_index) + } + fn validators() -> Vec<::AccountId> { >::validators() } @@ -885,6 +893,9 @@ impl SessionInterface for () { fn disable_validator(_: u32) -> bool { true } + fn enable_validator(_: u32) -> bool { + true + } fn validators() -> Vec { Vec::new() } @@ -995,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)) } } @@ -1270,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; @@ -1290,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) } } @@ -1305,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 @@ -1317,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 @@ -1325,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 2df3bc084eb0..2ae925d03643 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -27,8 +27,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, - InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, + Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced, + TryCollect, UnixTime, }, weights::Weight, }; @@ -50,7 +50,7 @@ use sp_staking::{ }; use crate::{ - election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, + asset, election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, @@ -96,7 +96,7 @@ impl Pallet { pub(crate) fn inspect_bond_state( stash: &T::AccountId, ) -> Result> { - let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + let lock = asset::staked::(&stash); let controller = >::get(stash).ok_or_else(|| { if lock == Zero::zero() { @@ -142,7 +142,7 @@ impl Pallet { pub fn weight_of_fn() -> Box VoteWeight> { // NOTE: changing this to unboxed `impl Fn(..)` return type and the pallet will still // compile, while some types in mock fail to resolve. - let issuance = T::Currency::total_issuance(); + let issuance = asset::total_issuance::(); Box::new(move |who: &T::AccountId| -> VoteWeight { Self::slashable_balance_of_vote_weight(who, issuance) }) @@ -150,7 +150,7 @@ impl Pallet { /// Same as `weight_of_fn`, but made for one time use. pub fn weight_of(who: &T::AccountId) -> VoteWeight { - let issuance = T::Currency::total_issuance(); + let issuance = asset::total_issuance::(); Self::slashable_balance_of_vote_weight(who, issuance) } @@ -164,7 +164,7 @@ impl Pallet { } else { // additional amount or actual balance of stash whichever is lower. additional.min( - T::Currency::free_balance(stash) + asset::stakeable_balance::(stash) .checked_sub(&ledger.total) .ok_or(ArithmeticError::Overflow)?, ) @@ -173,7 +173,7 @@ impl Pallet { ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; ledger.active = ledger.active.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; // last check: the new active amount of ledger must be more than ED. - ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); + ensure!(ledger.active >= asset::existential_deposit::(), Error::::InsufficientBond); // NOTE: ledger must be updated prior to calling `Self::weight_of`. ledger.update()?; @@ -193,12 +193,12 @@ 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; - let ed = T::Currency::minimum_balance(); + let ed = asset::existential_deposit::(); let used_weight = if ledger.unlocking.is_empty() && (ledger.active < ed || ledger.active.is_zero()) { // This account must have called `unbond()` with some value that caused the active @@ -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(); @@ -414,12 +416,12 @@ impl Pallet { let dest = Self::payee(StakingAccount::Stash(stash.clone()))?; let maybe_imbalance = match dest { - RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), + RewardDestination::Stash => asset::mint_existing::(stash, amount), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { ledger.active += amount; ledger.total += amount; - let r = T::Currency::deposit_into_existing(stash, amount).ok(); + let r = asset::mint_existing::(stash, amount); let _ = ledger .update() @@ -429,7 +431,7 @@ impl Pallet { }) .unwrap_or_default(), RewardDestination::Account(ref dest_account) => - Some(T::Currency::deposit_creating(&dest_account, amount)), + Some(asset::mint_creating::(&dest_account, amount)), RewardDestination::None => None, #[allow(deprecated)] RewardDestination::Controller => Self::bonded(stash) @@ -437,7 +439,7 @@ impl Pallet { defensive!("Paying out controller as reward destination which is deprecated and should be migrated."); // This should never happen once payees with a `Controller` variant have been migrated. // But if it does, just pay the controller account. - T::Currency::deposit_creating(&controller, amount) + asset::mint_creating::(&controller, amount) }), }; maybe_imbalance.map(|imbalance| (imbalance, dest)) @@ -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,8 +577,8 @@ 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 issuance = T::Currency::total_issuance(); + let staked = ErasTotalStake::::get(&active_era.index); + let issuance = asset::total_issuance::(); let (validator_payout, remainder) = T::EraPayout::era_payout(staked, issuance, era_duration); @@ -597,7 +599,7 @@ impl Pallet { // Set ending era reward. >::insert(&active_era.index, validator_payout); - T::RewardRemainder::on_unbalanced(T::Currency::issue(remainder)); + T::RewardRemainder::on_unbalanced(asset::issue::(remainder)); // Clear disabled validators. >::kill(); @@ -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); } @@ -748,7 +750,7 @@ impl Pallet { fn collect_exposures( supports: BoundedSupportsOf, ) -> BoundedVec<(T::AccountId, Exposure>), MaxWinnersOf> { - let total_issuance = T::Currency::total_issuance(); + let total_issuance = asset::total_issuance::(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) }; @@ -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; @@ -1581,7 +1583,7 @@ impl ScoreProvider for Pallet { // also, we play a trick to make sure that a issuance based-`CurrencyToVote` behaves well: // This will make sure that total issuance is zero, thus the currency to vote will be a 1-1 // conversion. - let imbalance = T::Currency::burn(T::Currency::total_issuance()); + let imbalance = asset::burn::(asset::total_issuance::()); // kinda ugly, but gets the job done. The fact that this works here is a HUGE exception. // Don't try this pattern in other places. core::mem::forget(imbalance); @@ -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 { @@ -1919,7 +1926,7 @@ impl StakingInterface for Pallet { impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_virtual_staker(who: &Self::AccountId) { - T::Currency::remove_lock(crate::STAKING_ID, who); + asset::kill_stake::(who); VirtualStakers::::insert(who, ()); } @@ -1956,12 +1963,7 @@ impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_direct_staker(who: &Self::AccountId) { assert!(VirtualStakers::::contains_key(who)); let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); - T::Currency::set_lock( - crate::STAKING_ID, - who, - ledger.total, - frame_support::traits::WithdrawReasons::all(), - ); + asset::update_stake::(who, ledger.total); VirtualStakers::::remove(who); } } @@ -2097,7 +2099,7 @@ impl Pallet { // ensure locks consistency. if VirtualStakers::::contains_key(stash.clone()) { ensure!( - T::Currency::balance_locked(crate::STAKING_ID, &stash) == Zero::zero(), + asset::staked::(&stash) == Zero::zero(), "virtual stakers should not have any locked balance" ); ensure!( @@ -2108,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!( @@ -2137,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!( @@ -2165,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(), @@ -2227,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() @@ -2297,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 8a4482f52ad5..b3f8c18f704c 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,8 +25,8 @@ use frame_election_provider_support::{ use frame_support::{ pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, + Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, + InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, @@ -38,6 +38,7 @@ use sp_runtime::{ }; use sp_staking::{ + offence::OffenceSeverity, EraIndex, Page, SessionIndex, StakingAccount::{self, Controller, Stash}, StakingInterface, @@ -48,11 +49,11 @@ mod impls; pub use impls::*; use crate::{ - slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, DisablingStrategy, - EraPayout, EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, - MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, - ValidatorPrefs, + asset, slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, + DisablingStrategy, EraPayout, EraRewardPoints, Exposure, ExposurePage, Forcing, + LedgerIntegrityState, MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, + PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, + UnlockChunk, ValidatorPrefs, }; // The speculative number of spans are used as an input of the weight annotation of @@ -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 @@ -779,7 +765,7 @@ pub mod pallet { status ); assert!( - T::Currency::free_balance(stash) >= balance, + asset::stakeable_balance::(stash) >= balance, "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( @@ -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 @@ -1023,14 +1168,14 @@ pub mod pallet { } // Reject a bond which is considered to be _dust_. - if value < T::Currency::minimum_balance() { + if value < asset::existential_deposit::() { return Err(Error::::InsufficientBond.into()) } // Would fail if account has no provider. frame_system::Pallet::::inc_consumers(&stash)?; - let stash_balance = T::Currency::free_balance(&stash); + let stash_balance = asset::stakeable_balance::(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let ledger = StakingLedger::::new(stash.clone(), value); @@ -1068,7 +1213,7 @@ pub mod pallet { /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond /// period ends. If this leaves an amount actively bonded less than - /// T::Currency::minimum_balance(), then it is increased to the full amount. + /// [`asset::existential_deposit`], then it is increased to the full amount. /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// @@ -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 @@ -1124,7 +1269,7 @@ pub mod pallet { ledger.active -= value; // Avoid there being a dust balance left in the staking system. - if ledger.active < T::Currency::minimum_balance() { + if ledger.active < asset::existential_deposit::() { value += ledger.active; ledger.active = Zero::zero(); } @@ -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, }; @@ -1654,7 +1799,10 @@ pub mod pallet { let initial_unlocking = ledger.unlocking.len() as u32; let (ledger, rebonded_value) = ledger.rebond(value); // Last check: the new active amount of ledger must be more than ED. - ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); + ensure!( + ledger.active >= asset::existential_deposit::(), + Error::::InsufficientBond + ); Self::deposit_event(Event::::Bonded { stash: ledger.stash.clone(), @@ -1706,8 +1854,8 @@ pub mod pallet { // virtual stakers should not be allowed to be reaped. ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); - let ed = T::Currency::minimum_balance(); - let origin_balance = T::Currency::total_balance(&stash); + let ed = asset::existential_deposit::(); + let origin_balance = asset::total_balance::(&stash); let ledger_total = Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default(); let reapable = origin_balance < ed || @@ -2074,8 +2222,8 @@ pub mod pallet { // cannot restore ledger for virtual stakers. ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); - let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); - let stash_balance = T::Currency::free_balance(&stash); + let current_lock = asset::staked::(&stash); + let stash_balance = asset::stakeable_balance::(&stash); let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { Ok(LedgerIntegrityState::Corrupted) => { @@ -2084,12 +2232,7 @@ pub mod pallet { let new_total = if let Some(total) = maybe_total { let new_total = total.min(stash_balance); // enforce lock == ledger.amount. - T::Currency::set_lock( - crate::STAKING_ID, - &stash, - new_total, - WithdrawReasons::all(), - ); + asset::update_stake::(&stash, new_total); new_total } else { current_lock @@ -2116,18 +2259,13 @@ pub mod pallet { // to enforce a new ledger.total and staking lock for this stash. let new_total = maybe_total.ok_or(Error::::CannotRestoreLedger)?.min(stash_balance); - T::Currency::set_lock( - crate::STAKING_ID, - &stash, - new_total, - WithdrawReasons::all(), - ); + asset::update_stake::(&stash, new_total); Ok((stash.clone(), new_total)) }, Err(Error::::BadState) => { // the stash and ledger do not exist but lock is lingering. - T::Currency::remove_lock(crate::STAKING_ID, &stash); + asset::kill_stake::(&stash); ensure!( Self::inspect_bond_state(&stash) == Err(Error::::NotStash), Error::::BadState diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 9bc8197c50b3..ae76b0707dcb 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -50,22 +50,22 @@ //! Based on research at use crate::{ - BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, NegativeImbalanceOf, - NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, - ValidatorSlashInEra, + asset, BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, + NegativeImbalanceOf, NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, + UnappliedSlash, ValidatorSlashInEra, }; use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, - traits::{Currency, Defensive, DefensiveSaturating, Imbalance, OnUnbalanced}, + traits::{Defensive, DefensiveSaturating, Imbalance, OnUnbalanced}, }; use scale_info::TypeInfo; 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, + }); } } }); @@ -578,7 +609,7 @@ pub fn do_slash( Err(_) => return, // nothing to do. }; - let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era); + let value = ledger.slash(value, asset::existential_deposit::(), slash_era); if value.is_zero() { // nothing to do return @@ -586,7 +617,7 @@ pub fn do_slash( // Skip slashing for virtual stakers. The pallets managing them should handle the slashing. if !Pallet::::is_virtual_staker(stash) { - let (imbalance, missing) = T::Currency::slash(stash, value); + let (imbalance, missing) = asset::slash::(stash, value); slashed_imbalance.subsume(imbalance); if !missing.is_zero() { @@ -656,7 +687,7 @@ fn pay_reporters( // this cancels out the reporter reward imbalance internally, leading // to no change in total issuance. - T::Currency::resolve_creating(reporter, reporter_reward); + asset::deposit_slashed::(reporter, reporter_reward); } // the rest goes to the on-slash imbalance handler (e.g. treasury) diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index 65aaa5f09de4..81337710aa90 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -28,7 +28,7 @@ use rand_chacha::{ use sp_io::hashing::blake2_256; use frame_election_provider_support::SortedListProvider; -use frame_support::{pallet_prelude::*, traits::Currency}; +use frame_support::pallet_prelude::*; use sp_runtime::{traits::StaticLookup, Perbill}; const SEED: u32 = 0; @@ -53,8 +53,8 @@ pub fn create_funded_user( balance_factor: u32, ) -> T::AccountId { let user = account(string, n, SEED); - let balance = T::Currency::minimum_balance() * balance_factor.into(); - let _ = T::Currency::make_free_balance_be(&user, balance); + let balance = asset::existential_deposit::() * balance_factor.into(); + let _ = asset::set_stakeable_balance::(&user, balance); user } @@ -65,7 +65,7 @@ pub fn create_funded_user_with_balance( balance: BalanceOf, ) -> T::AccountId { let user = account(string, n, SEED); - let _ = T::Currency::make_free_balance_be(&user, balance); + let _ = asset::set_stakeable_balance::(&user, balance); user } @@ -77,7 +77,7 @@ pub fn create_stash_controller( ) -> Result<(T::AccountId, T::AccountId), &'static str> { let staker = create_funded_user::("stash", n, balance_factor); let amount = - T::Currency::minimum_balance().max(1u64.into()) * (balance_factor / 10).max(1).into(); + asset::existential_deposit::().max(1u64.into()) * (balance_factor / 10).max(1).into(); Staking::::bond(RawOrigin::Signed(staker.clone()).into(), amount, destination)?; Ok((staker.clone(), staker)) } @@ -96,7 +96,7 @@ pub fn create_unique_stash_controller( } else { create_funded_user::("controller", n, balance_factor) }; - let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); + let amount = asset::existential_deposit::() * (balance_factor / 10).max(1).into(); Staking::::bond(RawOrigin::Signed(stash.clone()).into(), amount, destination)?; // update ledger to be a *different* controller to stash @@ -129,7 +129,7 @@ pub fn create_stash_and_dead_payee( let staker = create_funded_user::("stash", n, 0); // payee has no funds let payee = create_funded_user::("payee", n, 0); - let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); + let amount = asset::existential_deposit::() * (balance_factor / 10).max(1).into(); Staking::::bond( RawOrigin::Signed(staker.clone()).into(), amount, @@ -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 dd178a95bec5..6c2335e1aac8 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::{ConfigOp, Event, *}; -use crate::ledger::StakingLedgerInspect; +use crate::{asset, ledger::StakingLedgerInspect}; use frame_election_provider_support::{ bounds::{DataProviderBounds, ElectionBoundsBuilder}, ElectionProvider, SortedListProvider, Support, @@ -27,7 +27,7 @@ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, - traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, + traits::{Currency, Get, ReservableCurrency}, }; use mock::*; @@ -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,20 +220,20 @@ 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); // Account 10 has `balance_factor` free balance - assert_eq!(Balances::free_balance(10), 1); - assert_eq!(Balances::free_balance(10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); + 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); }); } @@ -311,9 +311,9 @@ fn change_controller_already_paired_once_stash() { #[test] fn rewards_should_work() { ExtBuilder::default().nominate(true).session_per_era(3).build_and_execute(|| { - let init_balance_11 = Balances::total_balance(&11); - let init_balance_21 = Balances::total_balance(&21); - let init_balance_101 = Balances::total_balance(&101); + let init_balance_11 = asset::total_balance::(&11); + let init_balance_21 = asset::total_balance::(&21); + let init_balance_101 = asset::total_balance::(&101); // Set payees Payee::::insert(11, RewardDestination::Account(11)); @@ -332,11 +332,11 @@ fn rewards_should_work() { start_session(1); assert_eq_uvec!(Session::validators(), vec![11, 21]); - assert_eq!(Balances::total_balance(&11), init_balance_11); - assert_eq!(Balances::total_balance(&21), init_balance_21); - assert_eq!(Balances::total_balance(&101), init_balance_101); + assert_eq!(asset::total_balance::(&11), init_balance_11); + 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(), @@ -363,17 +363,17 @@ fn rewards_should_work() { mock::make_all_reward_payment(0); assert_eq_error_rate!( - Balances::total_balance(&11), + asset::total_balance::(&11), init_balance_11 + part_for_11 * total_payout_0 * 2 / 3, 2, ); assert_eq_error_rate!( - Balances::total_balance(&21), + asset::total_balance::(&21), init_balance_21 + part_for_21 * total_payout_0 * 1 / 3, 2, ); assert_eq_error_rate!( - Balances::total_balance(&101), + asset::total_balance::(&101), init_balance_101 + part_for_101_from_11 * total_payout_0 * 2 / 3 + part_for_101_from_21 * total_payout_0 * 1 / 3, @@ -402,17 +402,17 @@ fn rewards_should_work() { mock::make_all_reward_payment(1); assert_eq_error_rate!( - Balances::total_balance(&11), + asset::total_balance::(&11), init_balance_11 + part_for_11 * (total_payout_0 * 2 / 3 + total_payout_1), 2, ); assert_eq_error_rate!( - Balances::total_balance(&21), + asset::total_balance::(&21), init_balance_21 + part_for_21 * total_payout_0 * 1 / 3, 2, ); assert_eq_error_rate!( - Balances::total_balance(&101), + asset::total_balance::(&101), init_balance_101 + part_for_101_from_11 * (total_payout_0 * 2 / 3 + total_payout_1) + part_for_101_from_21 * total_payout_0 * 1 / 3, @@ -429,7 +429,7 @@ fn staking_should_work() { // put some money in account that we'll use. for i in 1..5 { - let _ = Balances::make_free_balance_be(&i, 2000); + let _ = asset::set_stakeable_balance::(&i, 2000); } // --- Block 2: @@ -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); @@ -611,7 +611,7 @@ fn nominating_and_rewards_should_work() { // give the man some money let initial_balance = 1000; for i in [1, 3, 5, 11, 21].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); + let _ = asset::set_stakeable_balance::(&i, initial_balance); } // bond two account pairs and state interest in nomination. @@ -636,12 +636,12 @@ fn nominating_and_rewards_should_work() { assert_eq_uvec!(validator_controllers(), vec![21, 11]); // old validators must have already received some rewards. - let initial_balance_41 = Balances::total_balance(&41); - let mut initial_balance_21 = Balances::total_balance(&21); + let initial_balance_41 = asset::total_balance::(&41); + let mut initial_balance_21 = asset::total_balance::(&21); mock::make_all_reward_payment(0); - assert_eq!(Balances::total_balance(&41), initial_balance_41 + total_payout_0 / 2); - assert_eq!(Balances::total_balance(&21), initial_balance_21 + total_payout_0 / 2); - initial_balance_21 = Balances::total_balance(&21); + assert_eq!(asset::total_balance::(&41), initial_balance_41 + total_payout_0 / 2); + assert_eq!(asset::total_balance::(&21), initial_balance_21 + total_payout_0 / 2); + initial_balance_21 = asset::total_balance::(&21); assert_eq!(ErasStakersPaged::::iter_prefix_values((active_era(),)).count(), 2); assert_eq!( @@ -683,30 +683,30 @@ fn nominating_and_rewards_should_work() { // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 assert_eq_error_rate!( - Balances::total_balance(&1), + asset::total_balance::(&1), initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11), 2, ); // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 - assert_eq!(Balances::total_balance(&3), initial_balance); + assert_eq!(asset::total_balance::(&3), initial_balance); // 333 is the reward destination for 3. assert_eq_error_rate!( - Balances::total_balance(&333), + asset::total_balance::(&333), 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, 2 ); // Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 assert_eq_error_rate!( - Balances::total_balance(&11), + asset::total_balance::(&11), initial_balance + 5 * payout_for_11 / 9, 2, ); // Validator 21: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = // 5/11 assert_eq_error_rate!( - Balances::total_balance(&21), + asset::total_balance::(&21), initial_balance_21 + 5 * payout_for_21 / 11, 2, ); @@ -993,7 +993,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // Confirm account 11 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result @@ -1003,7 +1003,7 @@ fn cannot_transfer_staked_balance() { ); // Give account 11 extra free balance - let _ = Balances::make_free_balance_be(&11, 10000); + let _ = asset::set_stakeable_balance::(&11, 10000); // Confirm that account 11 can now transfer some balance assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1)); }); @@ -1018,7 +1018,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 is stashed assert_eq!(Staking::bonded(&21), Some(21)); // Confirm account 21 has some free balance - assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(asset::stakeable_balance::(&21), 2000); // Confirm account 21 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); // Confirm account 21 can transfer at most 1000 @@ -1037,14 +1037,14 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); // Give account 11 extra free balance - let _ = Balances::make_free_balance_be(&11, 10000); + let _ = asset::set_stakeable_balance::(&11, 10000); // Confirm account 11 can now reserve balance assert_ok!(Balances::reserve(&11, 1)); }); @@ -1057,9 +1057,9 @@ fn reward_destination_works() { // Check that account 11 is a validator assert!(Session::validators().contains(&11)); // Check the balance of the validator account - assert_eq!(Balances::free_balance(10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); // Check the balance of the stash account - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // Check how much is at stake assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1082,7 +1082,7 @@ fn reward_destination_works() { // Check that RewardDestination is Staked assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Staked)); // Check that reward went to the stash account of validator - assert_eq!(Balances::free_balance(11), 1000 + total_payout_0); + assert_eq!(asset::stakeable_balance::(&11), 1000 + total_payout_0); // Check that amount at stake increased accordingly assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -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); @@ -1111,7 +1111,7 @@ fn reward_destination_works() { // Check that RewardDestination is Stash assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Stash)); // Check that reward went to the stash account - assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1); + assert_eq!(asset::stakeable_balance::(&11), 1000 + total_payout_0 + total_payout_1); // Record this value let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; // Check that amount at stake is NOT increased @@ -1127,13 +1127,13 @@ 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)); // Check controller balance - assert_eq!(Balances::free_balance(11), 23150); + assert_eq!(asset::stakeable_balance::(&11), 23150); // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(reward_time_per_era()); @@ -1145,7 +1145,7 @@ fn reward_destination_works() { // Check that RewardDestination is Account(11) assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Account(11))); // Check that reward went to the controller account - assert_eq!(Balances::free_balance(11), recorded_stash_balance + total_payout_2); + assert_eq!(asset::stakeable_balance::(&11), recorded_stash_balance + total_payout_2); // Check that amount at stake is NOT increased assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -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]); }); } @@ -1179,8 +1179,8 @@ fn validator_payment_prefs_work() { mock::start_active_era(1); mock::make_all_reward_payment(0); - let balance_era_1_11 = Balances::total_balance(&11); - let balance_era_1_101 = Balances::total_balance(&101); + let balance_era_1_11 = asset::total_balance::(&11); + let balance_era_1_101 = asset::total_balance::(&101); // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); @@ -1194,8 +1194,16 @@ fn validator_payment_prefs_work() { let shared_cut = total_payout_1 - taken_cut; let reward_of_10 = shared_cut * exposure_1.own / exposure_1.total + taken_cut; let reward_of_100 = shared_cut * exposure_1.others[0].value / exposure_1.total; - assert_eq_error_rate!(Balances::total_balance(&11), balance_era_1_11 + reward_of_10, 2); - assert_eq_error_rate!(Balances::total_balance(&101), balance_era_1_101 + reward_of_100, 2); + assert_eq_error_rate!( + asset::total_balance::(&11), + balance_era_1_11 + reward_of_10, + 2 + ); + assert_eq_error_rate!( + asset::total_balance::(&101), + balance_era_1_101 + reward_of_100, + 2 + ); }); } @@ -1222,7 +1230,7 @@ fn bond_extra_works() { ); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // Call the bond_extra function from controller, add only 100 assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 100)); @@ -1284,13 +1292,13 @@ fn bond_extra_and_withdraw_unbonded_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // Initial config should be correct assert_eq!(active_era(), 0); // check the balance of a validator accounts. - assert_eq!(Balances::total_balance(&11), 1000000); + assert_eq!(asset::total_balance::(&11), 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1495,7 +1503,7 @@ fn rebond_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1621,7 +1629,7 @@ fn rebond_is_fifo() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1717,7 +1725,7 @@ fn rebond_emits_right_value_in_event() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1844,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)); @@ -1852,8 +1860,8 @@ fn reward_to_stake_works() { assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); // Give the man some money. - let _ = Balances::make_free_balance_be(&10, 1000); - let _ = Balances::make_free_balance_be(&20, 1000); + let _ = asset::set_stakeable_balance::(&10, 1000); + let _ = asset::set_stakeable_balance::(&20, 1000); // Bypass logic and change current exposure EraInfo::::set_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); @@ -1880,7 +1888,7 @@ fn reward_to_stake_works() { assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); - let _11_balance = Balances::free_balance(&11); + let _11_balance = asset::stakeable_balance::(&11); assert_eq!(_11_balance, 1000 + total_payout_0 / 2); // Trigger another new era as the info are frozen before the era start. @@ -1899,7 +1907,7 @@ fn reap_stash_works() { .balance_factor(10) .build_and_execute(|| { // given - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); + assert_eq!(asset::staked::(&11), 10 * 1000); assert_eq!(Staking::bonded(&11), Some(11)); assert!(>::contains_key(&11)); @@ -1926,7 +1934,7 @@ fn reap_stash_works() { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); // lock is removed. - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + assert_eq!(asset::staked::(&11), 0); }); } @@ -1937,7 +1945,7 @@ fn reap_stash_works_with_existential_deposit_zero() { .balance_factor(10) .build_and_execute(|| { // given - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); + assert_eq!(asset::staked::(&11), 10 * 1000); assert_eq!(Staking::bonded(&11), Some(11)); assert!(>::contains_key(&11)); @@ -1964,7 +1972,7 @@ fn reap_stash_works_with_existential_deposit_zero() { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); // lock is removed. - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + assert_eq!(asset::staked::(&11), 0); }); } @@ -2111,8 +2119,8 @@ fn bond_with_little_staked_value_bounded() { // setup assert_ok!(Staking::chill(RuntimeOrigin::signed(31))); assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); - let init_balance_1 = Balances::free_balance(&1); - let init_balance_11 = Balances::free_balance(&11); + let init_balance_1 = asset::stakeable_balance::(&1); + let init_balance_11 = asset::stakeable_balance::(&11); // Stingy validator. assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1))); @@ -2137,12 +2145,12 @@ fn bond_with_little_staked_value_bounded() { // Old ones are rewarded. assert_eq_error_rate!( - Balances::free_balance(11), + asset::stakeable_balance::(&11), init_balance_11 + total_payout_0 / 3, 1 ); // no rewards paid to 2. This was initial election. - assert_eq!(Balances::free_balance(1), init_balance_1); + assert_eq!(asset::stakeable_balance::(&1), init_balance_1); // reward era 2 let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); @@ -2155,12 +2163,12 @@ fn bond_with_little_staked_value_bounded() { // 2 is now rewarded. assert_eq_error_rate!( - Balances::free_balance(1), + asset::stakeable_balance::(&1), init_balance_1 + total_payout_1 / 3, 1 ); assert_eq_error_rate!( - Balances::free_balance(&11), + asset::stakeable_balance::(&11), init_balance_11 + total_payout_0 / 3 + total_payout_1 / 3, 2, ); @@ -2188,7 +2196,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); + let _ = asset::set_stakeable_balance::(&i, initial_balance); } assert_ok!(Staking::bond( @@ -2241,7 +2249,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); + let _ = asset::set_stakeable_balance::(&i, initial_balance); } assert_ok!(Staking::bond( @@ -2273,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()); @@ -2317,7 +2325,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { assert!(stake.checked_mul(reward_slash).is_none()); // Set staker - let _ = Balances::make_free_balance_be(&11, stake); + let _ = asset::set_stakeable_balance::(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let reward = EraRewardPoints:: { @@ -2330,11 +2338,11 @@ fn reward_validator_slashing_validator_does_not_overflow() { EraInfo::::set_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); - assert_eq!(Balances::total_balance(&11), stake * 2); + assert_eq!(asset::total_balance::(&11), stake * 2); // Set staker - let _ = Balances::make_free_balance_be(&11, stake); - let _ = Balances::make_free_balance_be(&2, stake); + let _ = asset::set_stakeable_balance::(&11, stake); + let _ = asset::set_stakeable_balance::(&2, stake); // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(RuntimeOrigin::signed(2), stake - 1, RewardDestination::Staked).unwrap(); @@ -2358,8 +2366,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { &[Perbill::from_percent(100)], ); - assert_eq!(Balances::total_balance(&11), stake - 1); - assert_eq!(Balances::total_balance(&2), 1); + assert_eq!(asset::total_balance::(&11), stake - 1); + assert_eq!(asset::total_balance::(&2), 1); }) } @@ -2423,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 ); @@ -2436,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 ); }); @@ -2457,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); }); } @@ -2465,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 { @@ -2475,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); }); } @@ -2499,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); @@ -2526,7 +2534,7 @@ fn slashing_performed_according_exposure() { ); // The stash account should be slashed for 250 (50% of 500). - assert_eq!(Balances::free_balance(11), 1000 - 250); + assert_eq!(asset::stakeable_balance::(&11), 1000 - 250); }); } @@ -2549,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)); @@ -2577,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 { @@ -2593,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); }); } @@ -2619,8 +2627,8 @@ fn reporters_receive_their_slice() { // 50% * (10% * initial_balance / 2) let reward = (initial_balance / 20) / 2; let reward_each = reward / 2; // split into two pieces. - assert_eq!(Balances::free_balance(1), 10 + reward_each); - assert_eq!(Balances::free_balance(2), 20 + reward_each); + assert_eq!(asset::stakeable_balance::(&1), 10 + reward_each); + assert_eq!(asset::stakeable_balance::(&2), 20 + reward_each); }); } @@ -2645,7 +2653,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - 0) // 50% * (10% * initial_balance * 20%) let reward = (initial_balance / 5) / 20; - assert_eq!(Balances::free_balance(1), 10 + reward); + assert_eq!(asset::stakeable_balance::(&1), 10 + reward); on_offence_now( &[OffenceDetails { @@ -2660,7 +2668,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(Balances::free_balance(1), 10 + prior_payout + reward); + assert_eq!(asset::stakeable_balance::(&1), 10 + prior_payout + reward); }); } @@ -2668,14 +2676,17 @@ fn subsequent_reports_in_same_span_pay_out_less() { fn invulnerables_are_not_slashed() { // For invulnerable validators no slashing is performed. ExtBuilder::default().invulnerables(vec![11]).build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&21), 2000); let exposure = Staking::eras_stakers(active_era(), &21); let initial_balance = Staking::slashable_balance_of(&21); - let nominator_balances: Vec<_> = - exposure.others.iter().map(|o| Balances::free_balance(&o.who)).collect(); + let nominator_balances: Vec<_> = exposure + .others + .iter() + .map(|o| asset::stakeable_balance::(&o.who)) + .collect(); on_offence_now( &[ @@ -2692,14 +2703,14 @@ fn invulnerables_are_not_slashed() { ); // The validator 11 hasn't been slashed, but 21 has been. - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // 2000 - (0.2 * initial_balance) - assert_eq!(Balances::free_balance(21), 2000 - (2 * initial_balance / 10)); + assert_eq!(asset::stakeable_balance::(&21), 2000 - (2 * initial_balance / 10)); // ensure that nominators were slashed as well. for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) { assert_eq!( - Balances::free_balance(&other.who), + asset::stakeable_balance::(&other.who), initial_balance - (2 * other.value / 10), ); } @@ -2710,7 +2721,7 @@ fn invulnerables_are_not_slashed() { fn dont_slash_if_fraction_is_zero() { // Don't slash if the fraction is zero. ExtBuilder::default().build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); on_offence_now( &[OffenceDetails { @@ -2721,8 +2732,8 @@ fn dont_slash_if_fraction_is_zero() { ); // The validator hasn't been slashed. The new era is not forced. - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); }); } @@ -2731,7 +2742,7 @@ fn only_slash_for_max_in_era() { // multiple slashes within one era are only applied if it is more than any previous slash in the // same era. ExtBuilder::default().build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); on_offence_now( &[OffenceDetails { @@ -2742,8 +2753,8 @@ fn only_slash_for_max_in_era() { ); // The validator has been slashed and has been force-chilled. - assert_eq!(Balances::free_balance(11), 500); - assert_eq!(Staking::force_era(), Forcing::NotForcing); + assert_eq!(asset::stakeable_balance::(&11), 500); + assert_eq!(ForceEra::::get(), Forcing::NotForcing); on_offence_now( &[OffenceDetails { @@ -2754,7 +2765,7 @@ fn only_slash_for_max_in_era() { ); // The validator has not been slashed additionally. - assert_eq!(Balances::free_balance(11), 500); + assert_eq!(asset::stakeable_balance::(&11), 500); on_offence_now( &[OffenceDetails { @@ -2765,7 +2776,7 @@ fn only_slash_for_max_in_era() { ); // The validator got slashed 10% more. - assert_eq!(Balances::free_balance(11), 400); + assert_eq!(asset::stakeable_balance::(&11), 400); }) } @@ -2776,7 +2787,7 @@ fn garbage_collection_after_slashing() { .existential_deposit(2) .balance_factor(2) .build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 2000); + assert_eq!(asset::stakeable_balance::(&11), 2000); on_offence_now( &[OffenceDetails { @@ -2786,7 +2797,7 @@ fn garbage_collection_after_slashing() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(11), 2000 - 200); + assert_eq!(asset::stakeable_balance::(&11), 2000 - 200); assert!(SlashingSpans::::get(&11).is_some()); assert_eq!(SpanSlash::::get(&(11, 0)).amount(), &200); @@ -2801,8 +2812,8 @@ fn garbage_collection_after_slashing() { // validator and nominator slash in era are garbage-collected by era change, // so we don't test those here. - assert_eq!(Balances::free_balance(11), 2); - assert_eq!(Balances::total_balance(&11), 2); + assert_eq!(asset::stakeable_balance::(&11), 2); + assert_eq!(asset::total_balance::(&11), 2); let slashing_spans = SlashingSpans::::get(&11).unwrap(); assert_eq!(slashing_spans.iter().count(), 2); @@ -2826,11 +2837,11 @@ fn garbage_collection_on_window_pruning() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let now = active_era(); let exposure = Staking::eras_stakers(now, &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2841,8 +2852,8 @@ fn garbage_collection_on_window_pruning() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - (nominated_value / 10)); assert!(ValidatorSlashInEra::::get(&now, &11).is_some()); assert!(NominatorSlashInEra::::get(&now, &101).is_some()); @@ -2867,9 +2878,9 @@ fn slashing_nominators_by_span_max() { mock::start_active_era(2); mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(21), 2000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&21), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let exposure_11 = Staking::eras_stakers(active_era(), &11); @@ -2886,10 +2897,10 @@ fn slashing_nominators_by_span_max() { 2, ); - assert_eq!(Balances::free_balance(11), 900); + assert_eq!(asset::stakeable_balance::(&11), 900); let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; - assert_eq!(Balances::free_balance(101), 2000 - slash_1_amount); + assert_eq!(asset::stakeable_balance::(&101), 2000 - slash_1_amount); let expected_spans = vec![ slashing::SlashingSpan { index: 1, start: 4, length: None }, @@ -2913,14 +2924,14 @@ fn slashing_nominators_by_span_max() { ); // 11 was not further slashed, but 21 and 101 were. - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(21), 1700); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&21), 1700); let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; assert!(slash_2_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount); + assert_eq!(asset::stakeable_balance::(&101), 2000 - slash_2_amount); // third slash: in same era and on same validator as first, higher // in-era value, but lower slash value than slash 2. @@ -2934,15 +2945,15 @@ fn slashing_nominators_by_span_max() { ); // 11 was further slashed, but 21 and 101 were not. - assert_eq!(Balances::free_balance(11), 800); - assert_eq!(Balances::free_balance(21), 1700); + assert_eq!(asset::stakeable_balance::(&11), 800); + assert_eq!(asset::stakeable_balance::(&21), 1700); let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; assert!(slash_3_amount < slash_2_amount); assert!(slash_3_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount); + assert_eq!(asset::stakeable_balance::(&101), 2000 - slash_2_amount); }); } @@ -2953,7 +2964,7 @@ fn slashes_are_summed_across_spans() { mock::start_active_era(2); mock::start_active_era(3); - assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(asset::stakeable_balance::(&21), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let get_span = |account| SlashingSpans::::get(&account).unwrap(); @@ -2972,7 +2983,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(21), 1900); + assert_eq!(asset::stakeable_balance::(&21), 1900); // 21 has been force-chilled. re-signal intent to validate. Staking::validate(RuntimeOrigin::signed(21), Default::default()).unwrap(); @@ -2996,7 +3007,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(21), 1810); + assert_eq!(asset::stakeable_balance::(&21), 1810); }); } @@ -3005,10 +3016,10 @@ fn deferred_slashes_are_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; System::reset_events(); @@ -3022,27 +3033,27 @@ 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!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(2); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. mock::start_active_era(4); - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - (nominated_value / 10)); assert!(matches!( staking_events_since_last_call().as_slice(), @@ -3067,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( @@ -3140,8 +3151,8 @@ fn staker_cannot_bail_deferred_slash() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let exposure = Staking::eras_stakers(active_era(), &11); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -3158,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!( @@ -3173,21 +3184,21 @@ fn staker_cannot_bail_deferred_slash() { ); // no slash yet. - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // no slash yet. mock::start_active_era(2); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); - assert_eq!(Staking::current_era().unwrap(), 2); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); + assert_eq!(CurrentEra::::get().unwrap(), 2); assert_eq!(active_era(), 2); // no slash yet. mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); - assert_eq!(Staking::current_era().unwrap(), 3); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); + assert_eq!(CurrentEra::::get().unwrap(), 3); assert_eq!(active_era(), 3); // and cannot yet unbond: @@ -3203,8 +3214,8 @@ fn staker_cannot_bail_deferred_slash() { // after being deferred for at least 2 full eras. mock::start_active_era(4); - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - (nominated_value / 10)); // and the leftover of the funds can now be unbonded. }) @@ -3215,10 +3226,10 @@ fn remove_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; // deferred to start of era 4. @@ -3227,8 +3238,8 @@ fn remove_deferred() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(2); @@ -3249,13 +3260,13 @@ fn remove_deferred() { // cancel one of them. assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0])); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. @@ -3280,8 +3291,8 @@ fn remove_deferred() { let actual_slash = total_slash - initial_slash; // 5% slash (15 - 10) processed now. - assert_eq!(Balances::free_balance(11), 950); - assert_eq!(Balances::free_balance(101), 2000 - actual_slash); + assert_eq!(asset::stakeable_balance::(&11), 950); + assert_eq!(asset::stakeable_balance::(&101), 2000 - actual_slash); }) } @@ -3290,10 +3301,10 @@ fn remove_multi_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], @@ -3363,11 +3374,11 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); // pre-slash balance - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + 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); @@ -3391,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 }, ] @@ -3398,8 +3410,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid // post-slash balance let nominator_slash_amount_11 = 125 / 10; - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - nominator_slash_amount_11); // check that validator was disabled. assert!(is_disabled(11)); @@ -3432,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( @@ -3442,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( @@ -3451,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(), @@ -3463,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 } ] @@ -3490,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![] }], @@ -3503,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)], @@ -3513,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(), @@ -3525,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), @@ -3534,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)); }); } @@ -3552,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 @@ -3561,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 @@ -3611,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![] }], @@ -3620,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)); @@ -3637,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(); @@ -3663,8 +3696,8 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Consumed weight for all payout_stakers dispatches that fail let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); - let init_balance_11 = Balances::total_balance(&11); - let init_balance_101 = Balances::total_balance(&101); + let init_balance_11 = asset::total_balance::(&11); + let init_balance_101 = asset::total_balance::(&101); let part_for_11 = Perbill::from_rational::(1000, 1125); let part_for_101 = Perbill::from_rational::(125, 1125); @@ -3702,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); @@ -3728,11 +3761,11 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // only era 1 and 2 can be rewarded. assert_eq!( - Balances::total_balance(&11), + asset::total_balance::(&11), init_balance_11 + part_for_11 * (total_payout_1 + total_payout_2), ); assert_eq!( - Balances::total_balance(&101), + asset::total_balance::(&101), init_balance_101 + part_for_101 * (total_payout_1 + total_payout_2), ); }); @@ -3749,24 +3782,24 @@ fn zero_slash_keeps_nominators() { .build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(0)], ); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // 11 is not removed but disabled 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]); }); } @@ -3825,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); }); } @@ -3837,7 +3870,7 @@ fn test_nominators_over_max_exposure_page_size_are_rewarded() { for i in 0..=MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - Balances::make_free_balance_be(&stash, balance); + asset::set_stakeable_balance::(&stash, balance); assert_ok!(Staking::bond( RuntimeOrigin::signed(stash), balance, @@ -3859,13 +3892,13 @@ fn test_nominators_over_max_exposure_page_size_are_rewarded() { while i < MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - assert!(Balances::free_balance(&stash) > balance); + assert!(asset::stakeable_balance::(&stash) > balance); i += 1; } // Assert overflowing nominators from page 1 are also rewarded let stash = 10_000 + i as AccountId; - assert!(Balances::free_balance(&stash) > (10_000 + i) as Balance); + assert!(asset::stakeable_balance::(&stash) > (10_000 + i) as Balance); }); } @@ -3878,7 +3911,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { for i in 0..nominator_count { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - Balances::make_free_balance_be(&stash, balance); + asset::set_stakeable_balance::(&stash, balance); assert_ok!(Staking::bond( RuntimeOrigin::signed(stash), balance, @@ -3900,9 +3933,10 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { // Assert all nominators are rewarded according to their stake for i in 0..nominator_count { // balance of the nominator after the reward payout. - let current_balance = Balances::free_balance(&((10000 + i) as AccountId)); + let current_balance = asset::stakeable_balance::(&((10000 + i) as AccountId)); // balance of the nominator in the previous iteration. - let previous_balance = Balances::free_balance(&((10000 + i - 1) as AccountId)); + let previous_balance = + asset::stakeable_balance::(&((10000 + i - 1) as AccountId)); // balance before the reward. let original_balance = 10_000 + i as Balance; @@ -3958,7 +3992,7 @@ fn test_multi_page_payout_stakers_by_page() { RewardOnUnbalanceWasCalled::set(false); System::reset_events(); - let controller_balance_before_p0_payout = Balances::free_balance(&11); + let controller_balance_before_p0_payout = asset::stakeable_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); @@ -3966,13 +4000,14 @@ 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 }, ] )); - let controller_balance_after_p0_payout = Balances::free_balance(&11); + let controller_balance_after_p0_payout = asset::stakeable_balance::(&11); // verify rewards have been paid out but still some left assert!(pallet_balances::TotalIssuance::::get() > pre_payout_total_issuance); @@ -3989,14 +4024,14 @@ 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 }, .. ] )); // verify the validator was not rewarded the second time - assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout); + assert_eq!(asset::stakeable_balance::(&11), controller_balance_after_p0_payout); // verify all rewards have been paid out assert_eq_error_rate!( @@ -4007,9 +4042,9 @@ fn test_multi_page_payout_stakers_by_page() { assert!(RewardOnUnbalanceWasCalled::get()); // Top 64 nominators of validator 11 automatically paid out, including the validator - assert!(Balances::free_balance(&11) > balance); + assert!(asset::stakeable_balance::(&11) > balance); for i in 0..100 { - assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance); + assert!(asset::stakeable_balance::(&(1000 + i)) > balance + i as Balance); } // verify we no longer track rewards in `legacy_claimed_rewards` vec @@ -4069,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(); @@ -4084,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 @@ -4094,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( @@ -4103,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( @@ -4112,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( @@ -4121,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]); }); } @@ -4178,7 +4213,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { let pre_payout_total_issuance = pallet_balances::TotalIssuance::::get(); RewardOnUnbalanceWasCalled::set(false); - let controller_balance_before_p0_payout = Balances::free_balance(&11); + let controller_balance_before_p0_payout = asset::stakeable_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // page 0 is claimed @@ -4187,7 +4222,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { Error::::AlreadyClaimed.with_weight(err_weight) ); - let controller_balance_after_p0_payout = Balances::free_balance(&11); + let controller_balance_after_p0_payout = asset::stakeable_balance::(&11); // verify rewards have been paid out but still some left assert!(pallet_balances::TotalIssuance::::get() > pre_payout_total_issuance); @@ -4206,7 +4241,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { ); // verify the validator was not rewarded the second time - assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout); + assert_eq!(asset::stakeable_balance::(&11), controller_balance_after_p0_payout); // verify all rewards have been paid out assert_eq_error_rate!( @@ -4218,9 +4253,9 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify all nominators of validator 11 are paid out, including the validator // Validator payout goes to controller. - assert!(Balances::free_balance(&11) > balance); + assert!(asset::stakeable_balance::(&11) > balance); for i in 0..100 { - assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance); + assert!(asset::stakeable_balance::(&(1000 + i)) > balance + i as Balance); } // verify we no longer track rewards in `legacy_claimed_rewards` vec @@ -4280,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(); @@ -4295,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 @@ -4304,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( @@ -4312,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( @@ -4321,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!( @@ -4350,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!( @@ -4362,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]); }); } @@ -4578,25 +4613,29 @@ fn test_commission_paid_across_pages() { let payout = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - let initial_balance = Balances::free_balance(&11); + let initial_balance = asset::stakeable_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); - let controller_balance_after_p0_payout = Balances::free_balance(&11); + let controller_balance_after_p0_payout = asset::stakeable_balance::(&11); // some commission is paid assert!(initial_balance < controller_balance_after_p0_payout); // payout all pages for i in 1..4 { - let before_balance = Balances::free_balance(&11); + let before_balance = asset::stakeable_balance::(&11); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i)); - let after_balance = Balances::free_balance(&11); + let after_balance = asset::stakeable_balance::(&11); // some commission is paid for every page assert!(before_balance < after_balance); } - assert_eq_error_rate!(Balances::free_balance(&11), initial_balance + payout / 2, 1,); + assert_eq_error_rate!( + asset::stakeable_balance::(&11), + initial_balance + payout / 2, + 1, + ); }); } @@ -4852,7 +4891,7 @@ fn payout_to_any_account_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(1234), RewardDestination::Account(42))); // Reward Destination account doesn't exist - assert_eq!(Balances::free_balance(42), 0); + assert_eq!(asset::stakeable_balance::(&42), 0); mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); @@ -4862,7 +4901,7 @@ fn payout_to_any_account_works() { assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Payment is successful - assert!(Balances::free_balance(42) > 0); + assert!(asset::stakeable_balance::(&42) > 0); }) } @@ -5661,9 +5700,9 @@ fn chill_other_works() { let a = 4 * i; let b = 4 * i + 2; let c = 4 * i + 3; - Balances::make_free_balance_be(&a, 100_000); - Balances::make_free_balance_be(&b, 100_000); - Balances::make_free_balance_be(&c, 100_000); + asset::set_stakeable_balance::(&a, 100_000); + asset::set_stakeable_balance::(&b, 100_000); + asset::set_stakeable_balance::(&c, 100_000); // Nominator assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash)); @@ -6859,7 +6898,7 @@ fn test_runtime_api_pending_rewards() { // Set staker for v in validator_one..=validator_three { - let _ = Balances::make_free_balance_be(&v, stake); + let _ = asset::set_stakeable_balance::(&v, stake); assert_ok!(Staking::bond(RuntimeOrigin::signed(v), stake, RewardDestination::Staked)); } @@ -6992,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 @@ -7049,7 +7089,7 @@ mod staking_interface { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); // lock is removed. - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + assert_eq!(asset::staked::(&11), 0); }); } @@ -7086,12 +7126,12 @@ mod staking_unchecked { fn virtual_bond_does_not_lock() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); // 10 can bond more than its balance amount since we do not require lock for virtual // bonding. assert_ok!(::virtual_bond(&10, 100, &15)); // nothing is locked on 10. - assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + assert_eq!(asset::staked::(&10), 0); // adding more balance does not lock anything as well. assert_ok!(::bond_extra(&10, 1000)); // but ledger is updated correctly. @@ -7118,7 +7158,7 @@ mod staking_unchecked { Ok(Stake { total: 1100, active: 900 }) ); // still no locks. - assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + assert_eq!(asset::staked::(&10), 0); mock::start_active_era(2); // cannot withdraw without waiting for unbonding period. @@ -7218,11 +7258,11 @@ mod staking_unchecked { fn migrate_virtual_staker() { ExtBuilder::default().build_and_execute(|| { // give some balance to 200 - Balances::make_free_balance_be(&200, 2000); + asset::set_stakeable_balance::(&200, 2000); // stake assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 1000, RewardDestination::Staked)); - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 1000); + assert_eq!(asset::staked::(&200), 1000); // migrate them to virtual staker ::migrate_to_virtual_staker(&200); @@ -7230,7 +7270,7 @@ mod staking_unchecked { assert_ok!(::set_payee(&200, &201)); // ensure the balance is not locked anymore - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 0); + assert_eq!(asset::staked::(&200), 0); // and they are marked as virtual stakers assert_eq!(Pallet::::is_virtual_staker(&200), true); @@ -7300,7 +7340,7 @@ mod staking_unchecked { assert!(is_disabled(11)); // but virtual nominator's balance is not slashed. - assert_eq!(Balances::free_balance(&101), nominator_balance); + assert_eq!(asset::stakeable_balance::(&101), nominator_balance); // but slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_share); }) @@ -7332,9 +7372,9 @@ mod staking_unchecked { assert_ok!(::set_payee(&101, &102)); // cache values - let validator_balance = Balances::free_balance(&11); + let validator_balance = asset::stakeable_balance::(&11); let validator_stake = Staking::ledger(11.into()).unwrap().total; - let nominator_balance = Balances::free_balance(&101); + let nominator_balance = asset::stakeable_balance::(&101); let nominator_stake = Staking::ledger(101.into()).unwrap().total; // 11 goes offline @@ -7353,14 +7393,14 @@ mod staking_unchecked { // all validator stake is slashed assert_eq_error_rate!( validator_balance - validator_stake, - Balances::free_balance(&11), + asset::stakeable_balance::(&11), 1 ); // Because slashing happened. assert!(is_disabled(11)); // Virtual nominator's balance is not slashed. - assert_eq!(Balances::free_balance(&101), nominator_balance); + assert_eq!(asset::stakeable_balance::(&101), nominator_balance); // Slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_stake); @@ -7900,7 +7940,7 @@ mod ledger_recovery { ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + let lock_333_before = asset::staked::(&333); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -7936,14 +7976,14 @@ mod ledger_recovery { // side effects on 333 - ledger, bonded, payee, lock should be completely empty. // however, 333 lock remains. - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // NOK + assert_eq!(asset::staked::(&333), lock_333_before); // NOK assert!(Bonded::::get(&333).is_none()); // OK assert!(Payee::::get(&333).is_none()); // OK assert!(Ledger::::get(&444).is_none()); // OK // side effects on 444 - ledger, bonded, payee, lock should remain be intact. // however, 444 lock was removed. - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // NOK + assert_eq!(asset::staked::(&444), 0); // NOK assert!(Bonded::::get(&444).is_some()); // OK assert!(Payee::::get(&444).is_some()); // OK assert!(Ledger::::get(&555).is_none()); // NOK @@ -7957,7 +7997,7 @@ mod ledger_recovery { ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + let lock_333_before = asset::staked::(&333); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -7992,14 +8032,15 @@ mod ledger_recovery { assert_eq!(Staking::inspect_bond_state(&444), Err(Error::::NotStash)); // side effects on 333 - ledger, bonded, payee, lock should be intact. - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK + 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. - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // OK + assert_eq!(asset::staked::(&444), 0); // OK assert!(Bonded::::get(&444).is_none()); // OK assert!(Payee::::get(&444).is_none()); // OK assert!(Ledger::::get(&555).is_none()); // OK @@ -8080,7 +8121,7 @@ mod ledger_recovery { setup_double_bonded_ledgers(); // ledger.total == lock - let total_444_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444); + let total_444_before_corruption = asset::staked::(&444); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -8182,8 +8223,8 @@ mod ledger_recovery { ExtBuilder::default().has_stakers(true).build_and_execute(|| { setup_double_bonded_ledgers(); - let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); - let lock_444_before = Balances::balance_locked(crate::STAKING_ID, &444); + let lock_333_before = asset::staked::(&333); + let lock_444_before = asset::staked::(&444); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -8203,16 +8244,13 @@ mod ledger_recovery { // if 444 bonds extra, the locks remain in sync. bond_extra_no_checks(&444, 40); - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); + assert_eq!(asset::staked::(&333), lock_333_before); + assert_eq!(asset::staked::(&444), lock_444_before + 40); // however if 333 bonds extra, the wrong lock is updated. bond_extra_no_checks(&333, 30); - assert_eq!( - Balances::balance_locked(crate::STAKING_ID, &333), - lock_444_before + 40 + 30 - ); //not OK - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); // OK + assert_eq!(asset::staked::(&333), lock_444_before + 40 + 30); //not OK + assert_eq!(asset::staked::(&444), lock_444_before + 40); // OK // recover the ledger bonded by 333 stash. Note that the total/lock needs to be // re-written since on-chain data lock has become out of sync. @@ -8247,9 +8285,9 @@ mod ledger_recovery { let ledger_444 = Bonded::::get(&444).and_then(Ledger::::get).unwrap(); assert_eq!(ledger_333.total, lock_333_before + 30); - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), ledger_333.total); + assert_eq!(asset::staked::(&333), ledger_333.total); assert_eq!(ledger_444.total, lock_444_before + 40); - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), ledger_444.total); + assert_eq!(asset::staked::(&444), ledger_444.total); // try-state checks are ok now. assert_ok!(Staking::do_try_state(System::block_number())); @@ -8261,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 @@ -8277,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!(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_eq!(disable_offender, Some(OFFENDER_VALIDATOR_IDX)); + 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/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/sudo/src/benchmarking.rs b/substrate/frame/sudo/src/benchmarking.rs index dee7d09c9d0c..cf96562a30cf 100644 --- a/substrate/frame/sudo/src/benchmarking.rs +++ b/substrate/frame/sudo/src/benchmarking.rs @@ -21,14 +21,25 @@ use super::*; use crate::Pallet; use alloc::{boxed::Box, vec}; use frame_benchmarking::v2::*; +use frame_support::dispatch::{DispatchInfo, GetDispatchInfo}; use frame_system::RawOrigin; +use sp_runtime::traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, +}; fn assert_last_event(generic_event: crate::Event) { let re: ::RuntimeEvent = generic_event.into(); frame_system::Pallet::::assert_last_event(re.into()); } -#[benchmarks(where ::RuntimeCall: From>)] +#[benchmarks(where + T: Send + Sync, + ::RuntimeCall: From>, + ::RuntimeCall: Dispatchable + GetDispatchInfo, + <::RuntimeCall as Dispatchable>::PostInfo: Default, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, +)] mod benchmarks { use super::*; @@ -86,5 +97,26 @@ mod benchmarks { assert_last_event::(Event::KeyRemoved {}); } + #[benchmark] + fn check_only_sudo_account() { + let caller: T::AccountId = whitelisted_caller(); + Key::::put(&caller); + + let call: ::RuntimeCall = + frame_system::Call::remark { remark: vec![] }.into(); + let info = call.get_dispatch_info(); + let ext = CheckOnlySudoAccount::::new(); + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok( + Default::default() + )) + .unwrap() + .is_ok()); + } + } + impl_benchmark_test_suite!(Pallet, crate::mock::new_bench_ext(), crate::mock::Test); } diff --git a/substrate/frame/sudo/src/extension.rs b/substrate/frame/sudo/src/extension.rs index fb7eaf789480..d2669de79e54 100644 --- a/substrate/frame/sudo/src/extension.rs +++ b/substrate/frame/sudo/src/extension.rs @@ -18,13 +18,14 @@ 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::{ - traits::{DispatchInfoOf, Dispatchable, SignedExtension}, + impl_tx_ext_default, + traits::{AsSystemOriginSigner, DispatchInfoOf, Dispatchable, TransactionExtension}, transaction_validity::{ - InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, - UnknownTransaction, ValidTransaction, + InvalidTransaction, TransactionPriority, TransactionValidityError, UnknownTransaction, + ValidTransaction, }, }; @@ -59,49 +60,62 @@ impl fmt::Debug for CheckOnlySudoAccount { } impl CheckOnlySudoAccount { - /// Creates new `SignedExtension` to check sudo key. + /// Creates new `TransactionExtension` to check sudo key. pub fn new() -> Self { Self::default() } } -impl SignedExtension for CheckOnlySudoAccount +impl TransactionExtension<::RuntimeCall> + for CheckOnlySudoAccount where - ::RuntimeCall: Dispatchable, + ::RuntimeCall: Dispatchable, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + Clone, { const IDENTIFIER: &'static str = "CheckOnlySudoAccount"; - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); type Pre = (); + type Val = (); - fn additional_signed(&self) -> Result { - Ok(()) + fn weight( + &self, + _: &::RuntimeCall, + ) -> frame_support::weights::Weight { + use crate::weights::WeightInfo; + T::WeightInfo::check_only_sudo_account() } fn validate( &self, - who: &Self::AccountId, - _call: &Self::Call, - info: &DispatchInfoOf, + origin: <::RuntimeCall as Dispatchable>::RuntimeOrigin, + _call: &::RuntimeCall, + info: &DispatchInfoOf<::RuntimeCall>, _len: usize, - ) -> TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + ( + ValidTransaction, + Self::Val, + <::RuntimeCall as Dispatchable>::RuntimeOrigin, + ), + TransactionValidityError, + > { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; let sudo_key: T::AccountId = Key::::get().ok_or(UnknownTransaction::CannotLookup)?; ensure!(*who == sudo_key, InvalidTransaction::BadSigner); - Ok(ValidTransaction { - priority: info.weight.ref_time() as TransactionPriority, - ..Default::default() - }) + Ok(( + ValidTransaction { + priority: info.total_weight().ref_time() as TransactionPriority, + ..Default::default() + }, + (), + origin, + )) } - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) - } + impl_tx_ext_default!(::RuntimeCall; prepare); } diff --git a/substrate/frame/sudo/src/lib.rs b/substrate/frame/sudo/src/lib.rs index 07296e90b648..66616bf801eb 100644 --- a/substrate/frame/sudo/src/lib.rs +++ b/substrate/frame/sudo/src/lib.rs @@ -85,8 +85,8 @@ //! meant to be used by constructing runtime calls from outside the runtime. //!
//! -//! This pallet also defines a [`SignedExtension`](sp_runtime::traits::SignedExtension) called -//! [`CheckOnlySudoAccount`] to ensure that only signed transactions by the sudo account are +//! This pallet also defines a [`TransactionExtension`](sp_runtime::traits::TransactionExtension) +//! called [`CheckOnlySudoAccount`] to ensure that only signed transactions by the sudo account are //! accepted by the transaction pool. The intended use of this signed extension is to prevent other //! accounts from spamming the transaction pool for the initial phase of a chain, during which //! developers may only want a sudo account to be able to make transactions. @@ -197,7 +197,7 @@ pub mod pallet { #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( - T::WeightInfo::sudo().saturating_add(dispatch_info.weight), + T::WeightInfo::sudo().saturating_add(dispatch_info.call_weight), dispatch_info.class ) })] @@ -262,7 +262,7 @@ pub mod pallet { #[pallet::weight({ let dispatch_info = call.get_dispatch_info(); ( - T::WeightInfo::sudo_as().saturating_add(dispatch_info.weight), + T::WeightInfo::sudo_as().saturating_add(dispatch_info.call_weight), dispatch_info.class, ) })] diff --git a/substrate/frame/sudo/src/tests.rs b/substrate/frame/sudo/src/tests.rs index 00bb86cc2686..3ed3bd336f53 100644 --- a/substrate/frame/sudo/src/tests.rs +++ b/substrate/frame/sudo/src/tests.rs @@ -108,7 +108,7 @@ fn sudo_unchecked_weight_basics() { let sudo_unchecked_weight_call = SudoCall::sudo_unchecked_weight { call, weight: Weight::from_parts(1_000, 0) }; let info = sudo_unchecked_weight_call.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(1_000, 0)); + assert_eq!(info.call_weight, Weight::from_parts(1_000, 0)); }); } diff --git a/substrate/frame/sudo/src/weights.rs b/substrate/frame/sudo/src/weights.rs index c166ab442d73..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: @@ -55,6 +55,7 @@ pub trait WeightInfo { fn sudo() -> Weight; fn sudo_as() -> Weight; fn remove_key() -> Weight; + fn check_only_sudo_account() -> Weight; } /// Weights for `pallet_sudo` using the Substrate node and recommended hardware. @@ -64,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)) } @@ -75,33 +76,43 @@ 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)) } + /// Storage: `Sudo::Key` (r:1 w:0) + /// 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: `198` + // Estimated: `1517` + // Minimum execution time: 4_903_000 picoseconds. + Weight::from_parts(5_046_000, 1517) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } } // For backwards compatibility and tests. @@ -110,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)) } @@ -121,31 +132,41 @@ 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)) } + /// Storage: `Sudo::Key` (r:1 w:0) + /// 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: `198` + // Estimated: `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 9e9741ee1619..d7da034b3492 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -71,6 +71,7 @@ pretty_assertions = { workspace = true } sp-timestamp = { workspace = true } frame-system = { workspace = true, default-features = true } sp-crypto-hashing = { workspace = true, default-features = true } +Inflector = { workspace = true } [features] default = ["std"] @@ -113,9 +114,7 @@ try-runtime = [ "sp-debug-derive/force-debug", "sp-runtime/try-runtime", ] -experimental = [ - "frame-support-procedural/experimental", -] +experimental = ["frame-support-procedural/experimental"] # By default some types have documentation, `no-metadata-docs` allows to reduce the documentation # in the metadata. no-metadata-docs = [ diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs index c5fe8440d21b..e34c6ac5016a 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/inherent.rs @@ -66,18 +66,16 @@ pub fn expand_outer_inherent( fn create_extrinsics(&self) -> #scrate::__private::Vec<<#block as #scrate::sp_runtime::traits::Block>::Extrinsic> { - use #scrate::inherent::ProvideInherent; + use #scrate::{inherent::ProvideInherent, traits::InherentBuilder}; let mut inherents = #scrate::__private::Vec::new(); #( #pallet_attrs if let Some(inherent) = #pallet_names::create_inherent(self) { - let inherent = <#unchecked_extrinsic as #scrate::sp_runtime::traits::Extrinsic>::new( + let inherent = <#unchecked_extrinsic as InherentBuilder>::new_inherent( inherent.into(), - None, - ).expect("Runtime UncheckedExtrinsic is not Opaque, so it has to return \ - `Some`; qed"); + ); inherents.push(inherent); } @@ -123,7 +121,7 @@ pub fn expand_outer_inherent( for xt in block.extrinsics() { // Inherents are before any other extrinsics. // And signed extrinsics are not inherents. - if #scrate::sp_runtime::traits::Extrinsic::is_signed(xt).unwrap_or(false) { + if !(#scrate::sp_runtime::traits::ExtrinsicLike::is_bare(xt)) { break } @@ -161,10 +159,9 @@ pub fn expand_outer_inherent( match #pallet_names::is_inherent_required(self) { Ok(Some(e)) => { let found = block.extrinsics().iter().any(|xt| { - let is_signed = #scrate::sp_runtime::traits::Extrinsic::is_signed(xt) - .unwrap_or(false); + let is_bare = #scrate::sp_runtime::traits::ExtrinsicLike::is_bare(xt); - if !is_signed { + if is_bare { let call = < #unchecked_extrinsic as ExtrinsicCall >::call(xt); @@ -209,8 +206,9 @@ pub fn expand_outer_inherent( use #scrate::inherent::ProvideInherent; use #scrate::traits::{IsSubType, ExtrinsicCall}; - if #scrate::sp_runtime::traits::Extrinsic::is_signed(ext).unwrap_or(false) { - // Signed extrinsics are never inherents. + let is_bare = #scrate::sp_runtime::traits::ExtrinsicLike::is_bare(ext); + if !is_bare { + // Inherents must be bare extrinsics. return false } 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 f3724f4ccb69..c12fc20bc8b8 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/metadata.rs @@ -49,6 +49,7 @@ pub fn expand_runtime_metadata( let event = expand_pallet_metadata_events(&filtered_names, runtime, decl); let constants = expand_pallet_metadata_constants(runtime, decl); let errors = expand_pallet_metadata_errors(runtime, decl); + let associated_types = expand_pallet_metadata_associated_types(runtime, decl); let docs = expand_pallet_metadata_docs(runtime, decl); let attr = decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| { let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original())) @@ -70,6 +71,7 @@ pub fn expand_runtime_metadata( constants: #constants, error: #errors, docs: #docs, + associated_types: #associated_types, deprecation_info: #deprecation_info, } } @@ -99,16 +101,16 @@ pub fn expand_runtime_metadata( let ty = #scrate::__private::scale_info::meta_type::<#extrinsic>(); let address_ty = #scrate::__private::scale_info::meta_type::< - <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureAddress + <#extrinsic as #scrate::traits::SignedTransactionBuilder>::Address >(); let call_ty = #scrate::__private::scale_info::meta_type::< - <#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::Call + <#extrinsic as #scrate::traits::ExtrinsicCall>::Call >(); let signature_ty = #scrate::__private::scale_info::meta_type::< - <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::Signature + <#extrinsic as #scrate::traits::SignedTransactionBuilder>::Signature >(); let extra_ty = #scrate::__private::scale_info::meta_type::< - <<#extrinsic as #scrate::sp_runtime::traits::Extrinsic>::SignaturePayload as #scrate::sp_runtime::traits::SignaturePayload>::SignatureExtra + <#extrinsic as #scrate::traits::SignedTransactionBuilder>::Extension >(); #scrate::__private::metadata_ir::MetadataIR { @@ -120,16 +122,20 @@ pub fn expand_runtime_metadata( call_ty, signature_ty, extra_ty, - signed_extensions: < + extensions: < < #extrinsic as #scrate::sp_runtime::traits::ExtrinsicMetadata - >::SignedExtensions as #scrate::sp_runtime::traits::SignedExtension + >::TransactionExtensions + as + #scrate::sp_runtime::traits::TransactionExtension::< + <#runtime as #system_path::Config>::RuntimeCall + > >::metadata() .into_iter() - .map(|meta| #scrate::__private::metadata_ir::SignedExtensionMetadataIR { + .map(|meta| #scrate::__private::metadata_ir::TransactionExtensionMetadataIR { identifier: meta.identifier, ty: meta.ty, - additional_signed: meta.additional_signed, + implicit: meta.implicit, }) .collect(), }, @@ -261,3 +267,12 @@ fn expand_pallet_metadata_docs(runtime: &Ident, decl: &Pallet) -> TokenStream { #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_documentation_metadata() } } + +fn expand_pallet_metadata_associated_types(runtime: &Ident, decl: &Pallet) -> TokenStream { + let path = &decl.path; + let instance = decl.instance.as_ref().into_iter(); + + quote! { + #path::Pallet::<#runtime #(, #path::#instance)*>::pallet_associated_types_metadata() + } +} diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs index 4a14853c04ee..1c4ab436ad92 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -153,6 +153,10 @@ pub fn expand_outer_origin( self.filter = #scrate::__private::Rc::new(#scrate::__private::Box::new(filter)); } + fn set_caller(&mut self, caller: OriginCaller) { + self.caller = caller; + } + fn set_caller_from(&mut self, other: impl Into) { self.caller = other.into().caller; } @@ -301,6 +305,22 @@ pub fn expand_outer_origin( } } + impl #scrate::__private::AsSystemOriginSigner<<#runtime as #system_path::Config>::AccountId> for RuntimeOrigin { + fn as_system_origin_signer(&self) -> Option<&<#runtime as #system_path::Config>::AccountId> { + if let OriginCaller::system(#system_path::Origin::<#runtime>::Signed(ref signed)) = &self.caller { + Some(signed) + } else { + None + } + } + } + + impl #scrate::__private::AsTransactionAuthorizedOrigin for RuntimeOrigin { + fn is_transaction_authorized(&self) -> bool { + !matches!(&self.caller, OriginCaller::system(#system_path::Origin::<#runtime>::None)) + } + } + #pallet_conversions }) } diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs index 6531c0e9e070..1302f86455f2 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs @@ -16,6 +16,7 @@ // limitations under the License use crate::construct_runtime::Pallet; +use core::str::FromStr; use proc_macro2::{Ident, TokenStream as TokenStream2}; use quote::quote; @@ -28,7 +29,8 @@ pub fn expand_outer_task( let mut from_impls = Vec::new(); let mut task_variants = Vec::new(); let mut variant_names = Vec::new(); - let mut task_paths = Vec::new(); + let mut task_types = Vec::new(); + let mut cfg_attrs = Vec::new(); for decl in pallet_decls { if decl.find_part("Task").is_none() { continue @@ -37,18 +39,31 @@ pub fn expand_outer_task( let variant_name = &decl.name; let path = &decl.path; let index = decl.index; + let instance = decl.instance.as_ref().map(|instance| quote!(, #path::#instance)); + let task_type = quote!(#path::Task<#runtime_name #instance>); + + let attr = decl.cfg_pattern.iter().fold(TokenStream2::new(), |acc, pattern| { + let attr = TokenStream2::from_str(&format!("#[cfg({})]", pattern.original())) + .expect("was successfully parsed before; qed"); + quote! { + #acc + #attr + } + }); from_impls.push(quote! { - impl From<#path::Task<#runtime_name>> for RuntimeTask { - fn from(hr: #path::Task<#runtime_name>) -> Self { + #attr + impl From<#task_type> for RuntimeTask { + fn from(hr: #task_type) -> Self { RuntimeTask::#variant_name(hr) } } - impl TryInto<#path::Task<#runtime_name>> for RuntimeTask { + #attr + impl TryInto<#task_type> for RuntimeTask { type Error = (); - fn try_into(self) -> Result<#path::Task<#runtime_name>, Self::Error> { + fn try_into(self) -> Result<#task_type, Self::Error> { match self { RuntimeTask::#variant_name(hr) => Ok(hr), _ => Err(()), @@ -58,13 +73,16 @@ pub fn expand_outer_task( }); task_variants.push(quote! { + #attr #[codec(index = #index)] - #variant_name(#path::Task<#runtime_name>), + #variant_name(#task_type), }); variant_names.push(quote!(#variant_name)); - task_paths.push(quote!(#path::Task)); + task_types.push(task_type); + + cfg_attrs.push(attr); } let prelude = quote!(#scrate::traits::tasks::__private); @@ -91,35 +109,50 @@ pub fn expand_outer_task( fn is_valid(&self) -> bool { match self { - #(RuntimeTask::#variant_names(val) => val.is_valid(),)* + #( + #cfg_attrs + RuntimeTask::#variant_names(val) => val.is_valid(), + )* _ => unreachable!(#INCOMPLETE_MATCH_QED), } } fn run(&self) -> Result<(), #scrate::traits::tasks::__private::DispatchError> { match self { - #(RuntimeTask::#variant_names(val) => val.run(),)* + #( + #cfg_attrs + RuntimeTask::#variant_names(val) => val.run(), + )* _ => unreachable!(#INCOMPLETE_MATCH_QED), } } fn weight(&self) -> #scrate::pallet_prelude::Weight { match self { - #(RuntimeTask::#variant_names(val) => val.weight(),)* + #( + #cfg_attrs + RuntimeTask::#variant_names(val) => val.weight(), + )* _ => unreachable!(#INCOMPLETE_MATCH_QED), } } fn task_index(&self) -> u32 { match self { - #(RuntimeTask::#variant_names(val) => val.task_index(),)* + #( + #cfg_attrs + RuntimeTask::#variant_names(val) => val.task_index(), + )* _ => unreachable!(#INCOMPLETE_MATCH_QED), } } fn iter() -> Self::Enumeration { let mut all_tasks = Vec::new(); - #(all_tasks.extend(#task_paths::iter().map(RuntimeTask::from).collect::>());)* + #( + #cfg_attrs + all_tasks.extend(<#task_types>::iter().map(RuntimeTask::from).collect::>()); + )* all_tasks.into_iter() } } diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index a2c1e6eec7f7..c2f546d92048 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -972,6 +972,15 @@ pub fn event(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// +/// Documentation for this macro can be found at `frame_support::pallet_macros::include_metadata`. +#[proc_macro_attribute] +pub fn include_metadata(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// /// --- /// diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index 8b333d19087d..87fb4b8967e6 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -253,13 +253,13 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { }) .collect::>(); - let feeless_check = methods.iter().map(|method| &method.feeless_check).collect::>(); - let feeless_check_result = - feeless_check.iter().zip(args_name.iter()).map(|(feeless_check, arg_name)| { - if let Some(feeless_check) = feeless_check { - quote::quote!(#feeless_check(origin, #( #arg_name, )*)) + let feeless_checks = methods.iter().map(|method| &method.feeless_check).collect::>(); + let feeless_check = + feeless_checks.iter().zip(args_name.iter()).map(|(feeless_check, arg_name)| { + if let Some(check) = feeless_check { + quote::quote_spanned!(span => #check) } else { - quote::quote!(false) + quote::quote_spanned!(span => |_origin, #( #arg_name, )*| { false }) } }); @@ -372,7 +372,8 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { >::pays_fee(&__pallet_base_weight, ( #( #args_name, )* )); #frame_support::dispatch::DispatchInfo { - weight: __pallet_weight, + call_weight: __pallet_weight, + extension_weight: Default::default(), class: __pallet_class, pays_fee: __pallet_pays_fee, } @@ -393,7 +394,8 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #( #cfg_attrs Self::#fn_name { #( #args_name_pattern_ref, )* } => { - #feeless_check_result + let feeless_check = #feeless_check; + feeless_check(origin, #( #args_name, )*) }, )* Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"), diff --git a/substrate/frame/support/procedural/src/pallet/expand/config.rs b/substrate/frame/support/procedural/src/pallet/expand/config.rs index 5cf4035a8f8b..0a583f1359ba 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/config.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/config.rs @@ -95,3 +95,51 @@ Consequently, a runtime that wants to include this pallet must implement this tr _ => Default::default(), } } + +/// Generate the metadata for the associated types of the config trait. +/// +/// Implements the `pallet_associated_types_metadata` function for the pallet. +pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream { + let frame_support = &def.frame_support; + let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site()); + let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site()); + let pallet_ident = &def.pallet_struct.pallet; + let trait_use_gen = &def.trait_use_generics(proc_macro2::Span::call_site()); + + let mut where_clauses = vec![&def.config.where_clause]; + where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause)); + let completed_where_clause = super::merge_where_clauses(&where_clauses); + + let types = def.config.associated_types_metadata.iter().map(|metadata| { + let ident = &metadata.ident; + let span = ident.span(); + let ident_str = ident.to_string(); + let cfgs = &metadata.cfg; + + let no_docs = vec![]; + let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &metadata.doc }; + + quote::quote_spanned!(span => { + #( #cfgs ) * + #frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR { + name: #ident_str, + ty: #frame_support::__private::scale_info::meta_type::< + ::#ident + >(), + docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ], + } + }) + }); + + quote::quote!( + impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause { + + #[doc(hidden)] + pub fn pallet_associated_types_metadata() + -> #frame_support::__private::sp_std::vec::Vec<#frame_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR> + { + #frame_support::__private::sp_std::vec![ #( #types ),* ] + } + } + ) +} diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 067839c28463..3f9b50f79c0c 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -60,6 +60,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let constants = constants::expand_constants(&mut def); let pallet_struct = pallet_struct::expand_pallet_struct(&mut def); let config = config::expand_config(&mut def); + let associated_types = config::expand_config_metadata(&def); let call = call::expand_call(&mut def); let tasks = tasks::expand_tasks(&mut def); let error = error::expand_error(&mut def); @@ -101,6 +102,7 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*] #constants #pallet_struct #config + #associated_types #call #tasks #error diff --git a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs index c6166ff45b19..79bf33a828e2 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -171,7 +171,7 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { let whitelisted_storage_idents: Vec = def .storages .iter() - .filter_map(|s| s.whitelisted.then_some(s.ident.clone())) + .filter_map(|s| s.whitelisted.then(|| s.ident.clone())) .collect(); let whitelisted_storage_keys_impl = quote::quote![ diff --git a/substrate/frame/support/procedural/src/pallet/expand/storage.rs b/substrate/frame/support/procedural/src/pallet/expand/storage.rs index e5bfa2793cbb..10e674c3cb19 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/storage.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/storage.rs @@ -427,15 +427,17 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { }; entries_builder.push(quote::quote_spanned!(storage.attr_span => #(#cfg_attrs)* - { - <#full_ident as #frame_support::storage::StorageEntryMetadataBuilder>::build_metadata( - #deprecation, - #frame_support::__private::vec![ - #( #docs, )* - ], - &mut entries, - ); - } + (|entries: &mut #frame_support::__private::Vec<_>| { + { + <#full_ident as #frame_support::storage::StorageEntryMetadataBuilder>::build_metadata( + #deprecation, + #frame_support::__private::vec![ + #( #docs, )* + ], + entries, + ); + } + }) )) } @@ -911,7 +913,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { entries: { #[allow(unused_mut)] let mut entries = #frame_support::__private::vec![]; - #( #entries_builder )* + #( #entries_builder(&mut entries); )* entries }, } diff --git a/substrate/frame/support/procedural/src/pallet/expand/tasks.rs b/substrate/frame/support/procedural/src/pallet/expand/tasks.rs index 7201c352d92c..b6346ca8ff34 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/tasks.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/tasks.rs @@ -20,21 +20,25 @@ //! Home of the expansion code for the Tasks API use crate::pallet::{parse::tasks::*, Def}; -use derive_syn_parse::Parse; use inflector::Inflector; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote, ToTokens}; -use syn::{parse_quote, spanned::Spanned, ItemEnum, ItemImpl}; +use syn::{parse_quote_spanned, spanned::Spanned}; impl TaskEnumDef { /// Since we optionally allow users to manually specify a `#[pallet::task_enum]`, in the /// event they _don't_ specify one (which is actually the most common behavior) we have to /// generate one based on the existing [`TasksDef`]. This method performs that generation. - pub fn generate( - tasks: &TasksDef, - type_decl_bounded_generics: TokenStream2, - type_use_generics: TokenStream2, - ) -> Self { + pub fn generate(tasks: &TasksDef, def: &Def) -> Self { + // We use the span of the attribute to indicate that the error comes from code generated + // for the specific section, otherwise the item impl. + let span = tasks + .tasks_attr + .as_ref() + .map_or_else(|| tasks.item_impl.span(), |attr| attr.span()); + + let type_decl_bounded_generics = def.type_decl_bounded_generics(span); + let variants = if tasks.tasks_attr.is_some() { tasks .tasks @@ -58,7 +62,8 @@ impl TaskEnumDef { } else { Vec::new() }; - let mut task_enum_def: TaskEnumDef = parse_quote! { + + parse_quote_spanned! { span => /// Auto-generated enum that encapsulates all tasks defined by this pallet. /// /// Conceptually similar to the [`Call`] enum, but for tasks. This is only @@ -69,33 +74,32 @@ impl TaskEnumDef { #variants, )* } - }; - task_enum_def.type_use_generics = type_use_generics; - task_enum_def + } } } -impl ToTokens for TaskEnumDef { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let item_enum = &self.item_enum; - let ident = &item_enum.ident; - let vis = &item_enum.vis; - let attrs = &item_enum.attrs; - let generics = &item_enum.generics; - let variants = &item_enum.variants; - let scrate = &self.scrate; - let type_use_generics = &self.type_use_generics; - if self.attr.is_some() { +impl TaskEnumDef { + fn expand_to_tokens(&self, def: &Def) -> TokenStream2 { + if let Some(attr) = &self.attr { + let ident = &self.item_enum.ident; + let vis = &self.item_enum.vis; + let attrs = &self.item_enum.attrs; + let generics = &self.item_enum.generics; + let variants = &self.item_enum.variants; + let frame_support = &def.frame_support; + let type_use_generics = &def.type_use_generics(attr.span()); + let type_impl_generics = &def.type_impl_generics(attr.span()); + // `item_enum` is short-hand / generated enum - tokens.extend(quote! { + quote! { #(#attrs)* #[derive( - #scrate::CloneNoBound, - #scrate::EqNoBound, - #scrate::PartialEqNoBound, - #scrate::pallet_prelude::Encode, - #scrate::pallet_prelude::Decode, - #scrate::pallet_prelude::TypeInfo, + #frame_support::CloneNoBound, + #frame_support::EqNoBound, + #frame_support::PartialEqNoBound, + #frame_support::pallet_prelude::Encode, + #frame_support::pallet_prelude::Decode, + #frame_support::pallet_prelude::TypeInfo, )] #[codec(encode_bound())] #[codec(decode_bound())] @@ -104,32 +108,25 @@ impl ToTokens for TaskEnumDef { #variants #[doc(hidden)] #[codec(skip)] - __Ignore(core::marker::PhantomData, #scrate::Never), + __Ignore(core::marker::PhantomData<(#type_use_generics)>, #frame_support::Never), } - impl core::fmt::Debug for #ident<#type_use_generics> { + impl<#type_impl_generics> core::fmt::Debug for #ident<#type_use_generics> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct(stringify!(#ident)).field("value", self).finish() } } - }); + } } else { // `item_enum` is a manually specified enum (no attribute) - tokens.extend(item_enum.to_token_stream()); + self.item_enum.to_token_stream() } } } -/// Represents an already-expanded [`TasksDef`]. -#[derive(Parse)] -pub struct ExpandedTasksDef { - pub task_item_impl: ItemImpl, - pub task_trait_impl: ItemImpl, -} - -impl ToTokens for TasksDef { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let scrate = &self.scrate; +impl TasksDef { + fn expand_to_tokens(&self, def: &Def) -> TokenStream2 { + let frame_support = &def.frame_support; let enum_ident = syn::Ident::new("Task", self.enum_ident.span()); let enum_arguments = &self.enum_arguments; let enum_use = quote!(#enum_ident #enum_arguments); @@ -160,21 +157,21 @@ impl ToTokens for TasksDef { let task_arg_names = self.tasks.iter().map(|task| &task.arg_names).collect::>(); let impl_generics = &self.item_impl.generics; - tokens.extend(quote! { + quote! { impl #impl_generics #enum_use { #(#task_fn_impls)* } - impl #impl_generics #scrate::traits::Task for #enum_use + impl #impl_generics #frame_support::traits::Task for #enum_use { - type Enumeration = #scrate::__private::IntoIter<#enum_use>; + type Enumeration = #frame_support::__private::IntoIter<#enum_use>; fn iter() -> Self::Enumeration { - let mut all_tasks = #scrate::__private::vec![]; + let mut all_tasks = #frame_support::__private::vec![]; #(all_tasks .extend(#task_iters.map(|(#(#task_arg_names),*)| #enum_ident::#task_fn_idents { #(#task_arg_names: #task_arg_names.clone()),* }) - .collect::<#scrate::__private::Vec<_>>()); + .collect::<#frame_support::__private::Vec<_>>()); )* all_tasks.into_iter() } @@ -193,7 +190,7 @@ impl ToTokens for TasksDef { } } - fn run(&self) -> Result<(), #scrate::pallet_prelude::DispatchError> { + fn run(&self) -> Result<(), #frame_support::pallet_prelude::DispatchError> { match self.clone() { #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => { <#enum_use>::#task_fn_names(#( #task_arg_names, )* ) @@ -203,64 +200,32 @@ impl ToTokens for TasksDef { } #[allow(unused_variables)] - fn weight(&self) -> #scrate::pallet_prelude::Weight { + fn weight(&self) -> #frame_support::pallet_prelude::Weight { match self.clone() { #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => #task_weights,)* Task::__Ignore(_, _) => unreachable!(), } } } - }); + } } } -/// Expands the [`TasksDef`] in the enclosing [`Def`], if present, and returns its tokens. -/// -/// This modifies the underlying [`Def`] in addition to returning any tokens that were added. -pub fn expand_tasks_impl(def: &mut Def) -> TokenStream2 { - let Some(tasks) = &mut def.tasks else { return quote!() }; - let ExpandedTasksDef { task_item_impl, task_trait_impl } = parse_quote!(#tasks); - quote! { - #task_item_impl - #task_trait_impl - } -} +/// Generate code related to tasks. +pub fn expand_tasks(def: &Def) -> TokenStream2 { + let Some(tasks_def) = &def.tasks else { + return quote!(); + }; -/// Represents a fully-expanded [`TaskEnumDef`]. -#[derive(Parse)] -pub struct ExpandedTaskEnum { - pub item_enum: ItemEnum, - pub debug_impl: ItemImpl, -} + let default_task_enum = TaskEnumDef::generate(&tasks_def, def); -/// Modifies a [`Def`] to expand the underlying [`TaskEnumDef`] if present, and also returns -/// its tokens. A blank [`TokenStream2`] is returned if no [`TaskEnumDef`] has been generated -/// or defined. -pub fn expand_task_enum(def: &mut Def) -> TokenStream2 { - let Some(task_enum) = &mut def.task_enum else { return quote!() }; - let ExpandedTaskEnum { item_enum, debug_impl } = parse_quote!(#task_enum); - quote! { - #item_enum - #debug_impl - } -} + let task_enum = def.task_enum.as_ref().unwrap_or_else(|| &default_task_enum); + + let tasks_expansion = tasks_def.expand_to_tokens(def); + let task_enum_expansion = task_enum.expand_to_tokens(def); -/// Modifies a [`Def`] to expand the underlying [`TasksDef`] and also generate a -/// [`TaskEnumDef`] if applicable. The tokens for these items are returned if they are created. -pub fn expand_tasks(def: &mut Def) -> TokenStream2 { - if let Some(tasks_def) = &def.tasks { - if def.task_enum.is_none() { - def.task_enum = Some(TaskEnumDef::generate( - &tasks_def, - def.type_decl_bounded_generics(tasks_def.item_impl.span()), - def.type_use_generics(tasks_def.item_impl.span()), - )); - } - } - let tasks_extra_output = expand_tasks_impl(def); - let task_enum_extra_output = expand_task_enum(def); quote! { - #tasks_extra_output - #task_enum_extra_output + #tasks_expansion + #task_enum_expansion } } diff --git a/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index 1975f059152c..6d53de3133e8 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -33,7 +33,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); - let task_part = def.task_enum.as_ref().map(|_| quote::quote!(Task,)); + let task_part = def.tasks.as_ref().map(|_| quote::quote!(Task,)); let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,)); @@ -85,7 +85,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { let call_part_v2 = def.call.as_ref().map(|_| quote::quote!(+ Call)); - let task_part_v2 = def.task_enum.as_ref().map(|_| quote::quote!(+ Task)); + let task_part_v2 = def.tasks.as_ref().map(|_| quote::quote!(+ Task)); let storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage)); diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index 9a59d7114202..6b6dcc802e2e 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -16,9 +16,9 @@ // limitations under the License. use super::helper; -use frame_support_procedural_tools::{get_doc_literals, is_using_frame_crate}; +use frame_support_procedural_tools::{get_cfg_attributes, get_doc_literals, is_using_frame_crate}; use quote::ToTokens; -use syn::{spanned::Spanned, token, Token}; +use syn::{spanned::Spanned, token, Token, TraitItemType}; /// List of additional token to be used for parsing. mod keyword { @@ -36,6 +36,7 @@ mod keyword { syn::custom_keyword!(no_default); syn::custom_keyword!(no_default_bounds); syn::custom_keyword!(constant); + syn::custom_keyword!(include_metadata); } #[derive(Default)] @@ -55,6 +56,8 @@ pub struct ConfigDef { pub has_instance: bool, /// Const associated type. pub consts_metadata: Vec, + /// Associated types metadata. + pub associated_types_metadata: Vec, /// Whether the trait has the associated type `Event`, note that those bounds are /// checked: /// * `IsType::RuntimeEvent` @@ -70,6 +73,26 @@ pub struct ConfigDef { pub default_sub_trait: Option, } +/// Input definition for an associated type in pallet config. +pub struct AssociatedTypeMetadataDef { + /// Name of the associated type. + pub ident: syn::Ident, + /// The doc associated. + pub doc: Vec, + /// The cfg associated. + pub cfg: Vec, +} + +impl From<&syn::TraitItemType> for AssociatedTypeMetadataDef { + fn from(trait_ty: &syn::TraitItemType) -> Self { + let ident = trait_ty.ident.clone(); + let doc = get_doc_literals(&trait_ty.attrs); + let cfg = get_cfg_attributes(&trait_ty.attrs); + + Self { ident, doc, cfg } + } +} + /// Input definition for a constant in pallet config. pub struct ConstMetadataDef { /// Name of the associated type. @@ -146,6 +169,8 @@ pub enum PalletAttrType { NoBounds(keyword::no_default_bounds), #[peek(keyword::constant, name = "constant")] Constant(keyword::constant), + #[peek(keyword::include_metadata, name = "include_metadata")] + IncludeMetadata(keyword::include_metadata), } /// Parsing for `#[pallet::X]` @@ -322,12 +347,32 @@ pub fn replace_self_by_t(input: proc_macro2::TokenStream) -> proc_macro2::TokenS .collect() } +/// Check that the trait item requires the `TypeInfo` bound (or similar). +fn contains_type_info_bound(ty: &TraitItemType) -> bool { + const KNOWN_TYPE_INFO_BOUNDS: &[&str] = &[ + // Explicit TypeInfo trait. + "TypeInfo", + // Implicit known substrate traits that implement type info. + // Note: Aim to keep this list as small as possible. + "Parameter", + ]; + + ty.bounds.iter().any(|bound| { + let syn::TypeParamBound::Trait(bound) = bound else { return false }; + + KNOWN_TYPE_INFO_BOUNDS + .iter() + .any(|known| bound.path.segments.last().map_or(false, |last| last.ident == *known)) + }) +} + impl ConfigDef { pub fn try_from( frame_system: &syn::Path, index: usize, item: &mut syn::Item, enable_default: bool, + disable_associated_metadata: bool, ) -> syn::Result { let syn::Item::Trait(item) = item else { let msg = "Invalid pallet::config, expected trait definition"; @@ -368,6 +413,7 @@ impl ConfigDef { let mut has_event_type = false; let mut consts_metadata = vec![]; + let mut associated_types_metadata = vec![]; let mut default_sub_trait = if enable_default { Some(DefaultTrait { items: Default::default(), @@ -383,6 +429,7 @@ impl ConfigDef { let mut already_no_default = false; let mut already_constant = false; let mut already_no_default_bounds = false; + let mut already_collected_associated_type = None; while let Ok(Some(pallet_attr)) = helper::take_first_item_pallet_attr::(trait_item) @@ -403,11 +450,29 @@ impl ConfigDef { trait_item.span(), "Invalid #[pallet::constant] in #[pallet::config], expected type item", )), + // Pallet developer has explicitly requested to include metadata for this associated type. + // + // They must provide a type item that implements `TypeInfo`. + (PalletAttrType::IncludeMetadata(_), syn::TraitItem::Type(ref typ)) => { + if already_collected_associated_type.is_some() { + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Duplicate #[pallet::include_metadata] attribute not allowed.", + )); + } + already_collected_associated_type = Some(pallet_attr._bracket.span.join()); + associated_types_metadata.push(AssociatedTypeMetadataDef::from(AssociatedTypeMetadataDef::from(typ))); + } + (PalletAttrType::IncludeMetadata(_), _) => + return Err(syn::Error::new( + pallet_attr._bracket.span.join(), + "Invalid #[pallet::include_metadata] in #[pallet::config], expected type item", + )), (PalletAttrType::NoDefault(_), _) => { if !enable_default { return Err(syn::Error::new( pallet_attr._bracket.span.join(), - "`#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` \ + "`#[pallet::no_default]` can only be used if `#[pallet::config(with_default)]` \ has been specified" )); } @@ -439,6 +504,47 @@ impl ConfigDef { } } + if let Some(span) = already_collected_associated_type { + // Events and constants are already propagated to the metadata + if is_event { + return Err(syn::Error::new( + span, + "Invalid #[pallet::include_metadata] for `type RuntimeEvent`. \ + The associated type `RuntimeEvent` is already collected in the metadata.", + )) + } + + if already_constant { + return Err(syn::Error::new( + span, + "Invalid #[pallet::include_metadata]: conflict with #[pallet::constant]. \ + Pallet constant already collect the metadata for the type.", + )) + } + + if let syn::TraitItem::Type(ref ty) = trait_item { + if !contains_type_info_bound(ty) { + let msg = format!( + "Invalid #[pallet::include_metadata] in #[pallet::config], collected type `{}` \ + does not implement `TypeInfo` or `Parameter`", + ty.ident, + ); + return Err(syn::Error::new(span, msg)); + } + } + } else { + // Metadata of associated types is collected by default, if the associated type + // implements `TypeInfo`, or a similar trait that requires the `TypeInfo` bound. + if !disable_associated_metadata && !is_event && !already_constant { + if let syn::TraitItem::Type(ref ty) = trait_item { + // Collect the metadata of the associated type if it implements `TypeInfo`. + if contains_type_info_bound(ty) { + associated_types_metadata.push(AssociatedTypeMetadataDef::from(ty)); + } + } + } + } + if !already_no_default && enable_default { default_sub_trait .as_mut() @@ -481,6 +587,7 @@ impl ConfigDef { index, has_instance, consts_metadata, + associated_types_metadata, has_event_type, where_clause, default_sub_trait, diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index b9c7afcab0f9..c9a150effccb 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -108,12 +108,13 @@ impl Def { let pallet_attr: Option = helper::take_first_item_pallet_attr(item)?; match pallet_attr { - Some(PalletAttr::Config(_, with_default)) if config.is_none() => + Some(PalletAttr::Config{ with_default, without_automatic_metadata, ..}) if config.is_none() => config = Some(config::ConfigDef::try_from( &frame_system, index, item, with_default, + without_automatic_metadata, )?), Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => { let p = pallet_struct::PalletStructDef::try_from(span, index, item)?; @@ -125,11 +126,11 @@ impl Def { }, Some(PalletAttr::RuntimeCall(cw, span)) if call.is_none() => call = Some(call::CallDef::try_from(span, index, item, dev_mode, cw)?), - Some(PalletAttr::Tasks(_)) if tasks.is_none() => { + Some(PalletAttr::Tasks(span)) if tasks.is_none() => { let item_tokens = item.to_token_stream(); // `TasksDef::parse` needs to know if attr was provided so we artificially // re-insert it here - tasks = Some(syn::parse2::(quote::quote! { + tasks = Some(syn::parse2::(quote::quote_spanned! { span => #[pallet::tasks_experimental] #item_tokens })?); @@ -403,6 +404,9 @@ impl Def { if let Some(extra_constants) = &self.extra_constants { instances.extend_from_slice(&extra_constants.instances[..]); } + if let Some(task_enum) = &self.task_enum { + instances.push(task_enum.instance_usage.clone()); + } let mut errors = instances.into_iter().filter_map(|instances| { if instances.has_instance == self.config.has_instance { @@ -547,6 +551,7 @@ mod keyword { syn::custom_keyword!(event); syn::custom_keyword!(config); syn::custom_keyword!(with_default); + syn::custom_keyword!(without_automatic_metadata); syn::custom_keyword!(hooks); syn::custom_keyword!(inherent); syn::custom_keyword!(error); @@ -560,10 +565,37 @@ mod keyword { syn::custom_keyword!(composite_enum); } +/// The possible values for the `#[pallet::config]` attribute. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum ConfigValue { + /// `#[pallet::config(with_default)]` + WithDefault(keyword::with_default), + /// `#[pallet::config(without_automatic_metadata)]` + WithoutAutomaticMetadata(keyword::without_automatic_metadata), +} + +impl syn::parse::Parse for ConfigValue { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + + if lookahead.peek(keyword::with_default) { + input.parse().map(ConfigValue::WithDefault) + } else if lookahead.peek(keyword::without_automatic_metadata) { + input.parse().map(ConfigValue::WithoutAutomaticMetadata) + } else { + Err(lookahead.error()) + } + } +} + /// Parse attributes for item in pallet module /// syntax must be `pallet::` (e.g. `#[pallet::config]`) enum PalletAttr { - Config(proc_macro2::Span, bool), + Config { + span: proc_macro2::Span, + with_default: bool, + without_automatic_metadata: bool, + }, Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), /// A `#[pallet::call]` with optional attributes to specialize the behaviour. @@ -625,7 +657,7 @@ enum PalletAttr { impl PalletAttr { fn span(&self) -> proc_macro2::Span { match self { - Self::Config(span, _) => *span, + Self::Config { span, .. } => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, Self::Tasks(span) => *span, @@ -660,13 +692,49 @@ impl syn::parse::Parse for PalletAttr { let lookahead = content.lookahead1(); if lookahead.peek(keyword::config) { let span = content.parse::()?.span(); - let with_default = content.peek(syn::token::Paren); - if with_default { + if content.peek(syn::token::Paren) { let inside_config; + + // Parse (with_default, without_automatic_metadata) attributes. let _paren = syn::parenthesized!(inside_config in content); - inside_config.parse::()?; + + let fields: syn::punctuated::Punctuated = + inside_config.parse_terminated(ConfigValue::parse, syn::Token![,])?; + let config_values = fields.iter().collect::>(); + + let mut with_default = false; + let mut without_automatic_metadata = false; + for config in config_values { + match config { + ConfigValue::WithDefault(_) => { + if with_default { + return Err(syn::Error::new( + span, + "Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: with_default.", + )); + } + with_default = true; + }, + ConfigValue::WithoutAutomaticMetadata(_) => { + if without_automatic_metadata { + return Err(syn::Error::new( + span, + "Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata.", + )); + } + without_automatic_metadata = true; + }, + } + } + + Ok(PalletAttr::Config { span, with_default, without_automatic_metadata }) + } else { + Ok(PalletAttr::Config { + span, + with_default: false, + without_automatic_metadata: false, + }) } - Ok(PalletAttr::Config(span, with_default)) } else if lookahead.peek(keyword::pallet) { Ok(PalletAttr::Pallet(content.parse::()?.span())) } else if lookahead.peek(keyword::hooks) { diff --git a/substrate/frame/support/procedural/src/pallet/parse/tasks.rs b/substrate/frame/support/procedural/src/pallet/parse/tasks.rs index ed860849a4db..5bff64643df1 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/tasks.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/tasks.rs @@ -25,8 +25,8 @@ use crate::assert_parse_error_matches; #[cfg(test)] use crate::pallet::parse::tests::simulate_manifest_dir; +use super::helper; use derive_syn_parse::Parse; -use frame_support_procedural_tools::generate_access_from_frame_or_crate; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens}; use syn::{ @@ -34,8 +34,8 @@ use syn::{ parse2, spanned::Spanned, token::{Bracket, Paren, PathSep, Pound}, - Error, Expr, Ident, ImplItem, ImplItemFn, ItemEnum, ItemImpl, LitInt, Path, PathArguments, - Result, TypePath, + Error, Expr, Ident, ImplItem, ImplItemFn, ItemEnum, ItemImpl, LitInt, PathArguments, Result, + TypePath, }; pub mod keywords { @@ -57,8 +57,6 @@ pub struct TasksDef { pub tasks_attr: Option, pub tasks: Vec, pub item_impl: ItemImpl, - /// Path to `frame_support` - pub scrate: Path, pub enum_ident: Ident, pub enum_arguments: PathArguments, } @@ -114,11 +112,7 @@ impl syn::parse::Parse for TasksDef { let enum_ident = last_seg.ident.clone(); let enum_arguments = last_seg.arguments.clone(); - // We do this here because it would be improper to do something fallible like this at - // the expansion phase. Fallible stuff should happen during parsing. - let scrate = generate_access_from_frame_or_crate("frame-support")?; - - Ok(TasksDef { tasks_attr, item_impl, tasks, scrate, enum_ident, enum_arguments }) + Ok(TasksDef { tasks_attr, item_impl, tasks, enum_ident, enum_arguments }) } } @@ -146,12 +140,11 @@ pub type PalletTaskEnumAttr = PalletTaskAttr; /// Parsing for a manually-specified (or auto-generated) task enum, optionally including the /// attached `#[pallet::task_enum]` attribute. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct TaskEnumDef { pub attr: Option, pub item_enum: ItemEnum, - pub scrate: Path, - pub type_use_generics: TokenStream2, + pub instance_usage: helper::InstanceUsage, } impl syn::parse::Parse for TaskEnumDef { @@ -163,13 +156,10 @@ impl syn::parse::Parse for TaskEnumDef { None => None, }; - // We do this here because it would be improper to do something fallible like this at - // the expansion phase. Fallible stuff should happen during parsing. - let scrate = generate_access_from_frame_or_crate("frame-support")?; - - let type_use_generics = quote!(T); + let instance_usage = + helper::check_type_def_gen(&item_enum.generics, item_enum.ident.span())?; - Ok(TaskEnumDef { attr, item_enum, scrate, type_use_generics }) + Ok(TaskEnumDef { attr, item_enum, instance_usage }) } } @@ -896,7 +886,7 @@ fn test_parse_task_enum_def_non_task_name() { simulate_manifest_dir("../../examples/basic", || { parse2::(quote! { #[pallet::task_enum] - pub enum Something { + pub enum Something { Foo } }) @@ -921,7 +911,7 @@ fn test_parse_task_enum_def_missing_attr_allowed() { fn test_parse_task_enum_def_missing_attr_alternate_name_allowed() { simulate_manifest_dir("../../examples/basic", || { parse2::(quote! { - pub enum Foo { + pub enum Foo { Red, } }) @@ -951,7 +941,7 @@ fn test_parse_task_enum_def_wrong_item() { assert_parse_error_matches!( parse2::(quote! { #[pallet::task_enum] - pub struct Something; + pub struct Something; }), "expected `enum`" ); diff --git a/substrate/frame/support/procedural/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index ea53335a88fd..d1d7efaab01d 100644 --- a/substrate/frame/support/procedural/tools/src/lib.rs +++ b/substrate/frame/support/procedural/tools/src/lib.rs @@ -181,3 +181,17 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { }) .collect() } + +/// Return all cfg attributes literals found. +pub fn get_cfg_attributes(attrs: &[syn::Attribute]) -> Vec { + attrs + .iter() + .filter_map(|attr| { + if let syn::Meta::List(meta) = &attr.meta { + meta.path.get_ident().filter(|ident| *ident == "cfg").map(|_| attr.clone()) + } else { + None + } + }) + .collect() +} diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index 351ba3a15efc..483a3dce77f6 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -26,7 +26,9 @@ use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_runtime::{ generic::{CheckedExtrinsic, UncheckedExtrinsic}, - traits::SignedExtension, + traits::{ + Dispatchable, ExtensionPostDispatchWeightHandler, RefundWeight, TransactionExtension, + }, DispatchError, RuntimeDebug, }; use sp_weights::Weight; @@ -236,14 +238,23 @@ impl<'a> OneOrMany for &'a [DispatchClass] { /// A bundle of static information collected from the `#[pallet::weight]` attributes. #[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] pub struct DispatchInfo { - /// Weight of this transaction. - pub weight: Weight, + /// Weight of this transaction's call. + pub call_weight: Weight, + /// Weight of this transaction's extension. + pub extension_weight: Weight, /// Class of this transaction. pub class: DispatchClass, /// Does this transaction pay fees. pub pays_fee: Pays, } +impl DispatchInfo { + /// Returns the weight used by this extrinsic's extension and call when applied. + pub fn total_weight(&self) -> Weight { + self.call_weight.saturating_add(self.extension_weight) + } +} + /// A `Dispatchable` function (aka transaction) that can carry some static information along with /// it, using the `#[pallet::weight]` attribute. pub trait GetDispatchInfo { @@ -268,7 +279,8 @@ pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &Dispatc .calc_actual_weight(info) } -/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. +/// Extract the actual pays_fee from a dispatch result if any or fall back to the default +/// weight. pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { match result { Ok(post_info) => post_info, @@ -290,15 +302,15 @@ pub struct PostDispatchInfo { impl PostDispatchInfo { /// Calculate how much (if any) weight was not used by the `Dispatchable`. pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight { - info.weight - self.calc_actual_weight(info) + info.total_weight() - self.calc_actual_weight(info) } /// Calculate how much weight was actually spent by the `Dispatchable`. pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight { if let Some(actual_weight) = self.actual_weight { - actual_weight.min(info.weight) + actual_weight.min(info.total_weight()) } else { - info.weight + info.total_weight() } } @@ -368,39 +380,28 @@ where } /// Implementation for unchecked extrinsic. -impl GetDispatchInfo - for UncheckedExtrinsic +impl> GetDispatchInfo + for UncheckedExtrinsic where - Call: GetDispatchInfo, - Extra: SignedExtension, + Call: GetDispatchInfo + Dispatchable, { fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() + let mut info = self.function.get_dispatch_info(); + info.extension_weight = self.extension_weight(); + info } } /// Implementation for checked extrinsic. -impl GetDispatchInfo for CheckedExtrinsic +impl> GetDispatchInfo + for CheckedExtrinsic where Call: GetDispatchInfo, { fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() - } -} - -/// Implementation for test extrinsic. -#[cfg(feature = "std")] -impl GetDispatchInfo - for sp_runtime::testing::TestXt -{ - fn get_dispatch_info(&self) -> DispatchInfo { - // for testing: weight == size. - DispatchInfo { - weight: Weight::from_parts(self.encode().len() as _, 0), - pays_fee: Pays::Yes, - class: self.call.get_dispatch_info().class, - } + let mut info = self.function.get_dispatch_info(); + info.extension_weight = self.extension_weight(); + info } } @@ -579,6 +580,28 @@ impl ClassifyDispatch for (Weight, DispatchClass, Pays) { } } +impl RefundWeight for PostDispatchInfo { + fn refund(&mut self, weight: Weight) { + if let Some(actual_weight) = self.actual_weight.as_mut() { + actual_weight.saturating_reduce(weight); + } + } +} + +impl ExtensionPostDispatchWeightHandler for PostDispatchInfo { + fn set_extension_weight(&mut self, info: &DispatchInfo) { + let actual_weight = self + .actual_weight + .unwrap_or(info.call_weight) + .saturating_add(info.extension_weight); + self.actual_weight = Some(actual_weight); + } +} + +impl ExtensionPostDispatchWeightHandler<()> for PostDispatchInfo { + fn set_extension_weight(&mut self, _: &()) {} +} + // TODO: Eventually remove these impl ClassifyDispatch for u64 { @@ -752,6 +775,19 @@ mod weight_tests { pub fn f21(_origin: OriginFor) -> DispatchResult { unimplemented!(); } + + #[pallet::weight(1000)] + pub fn f99(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + + #[pallet::weight(1000)] + pub fn f100(_origin: OriginFor) -> DispatchResultWithPostInfo { + Ok(crate::dispatch::PostDispatchInfo { + actual_weight: Some(Weight::from_parts(500, 0)), + pays_fee: Pays::Yes, + }) + } } pub mod pallet_prelude { @@ -801,57 +837,61 @@ mod weight_tests { fn weights_are_correct() { // #[pallet::weight(1000)] let info = Call::::f00 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(1000, 0)); + assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); // #[pallet::weight((1000, DispatchClass::Mandatory))] let info = Call::::f01 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(1000, 0)); + assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); assert_eq!(info.class, DispatchClass::Mandatory); assert_eq!(info.pays_fee, Pays::Yes); // #[pallet::weight((1000, Pays::No))] let info = Call::::f02 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(1000, 0)); + assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::No); // #[pallet::weight((1000, DispatchClass::Operational, Pays::No))] let info = Call::::f03 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(1000, 0)); + assert_eq!(info.total_weight(), Weight::from_parts(1000, 0)); assert_eq!(info.class, DispatchClass::Operational); assert_eq!(info.pays_fee, Pays::No); // #[pallet::weight(((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes))] let info = Call::::f11 { a: 13, eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(150, 0)); // 13*10 + 20 + assert_eq!(info.total_weight(), Weight::from_parts(150, 0)); // 13*10 + 20 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); // #[pallet::weight((0, DispatchClass::Operational, Pays::Yes))] let info = Call::::f12 { a: 10, eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, Weight::zero()); + assert_eq!(info.total_weight(), Weight::zero()); assert_eq!(info.class, DispatchClass::Operational); assert_eq!(info.pays_fee, Pays::Yes); // #[pallet::weight(T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + // Weight::from_all(10_000))] let info = Call::::f20 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(12300, 10000)); // 100*3 + 1000*2 + 10_1000 + assert_eq!(info.total_weight(), Weight::from_parts(12300, 10000)); // 100*3 + 1000*2 + 10_1000 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); // #[pallet::weight(T::DbWeight::get().reads_writes(6, 5) + Weight::from_all(40_000))] let info = Call::::f21 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_parts(45600, 40000)); // 100*6 + 1000*5 + 40_1000 + assert_eq!(info.total_weight(), Weight::from_parts(45600, 40000)); // 100*6 + 1000*5 + 40_1000 assert_eq!(info.class, DispatchClass::Normal); assert_eq!(info.pays_fee, Pays::Yes); } #[test] fn extract_actual_weight_works() { - let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; + let pre = DispatchInfo { + call_weight: Weight::from_parts(1000, 0), + extension_weight: Weight::zero(), + ..Default::default() + }; assert_eq!( extract_actual_weight(&Ok(from_actual_ref_time(Some(7))), &pre), Weight::from_parts(7, 0) @@ -871,7 +911,11 @@ mod weight_tests { #[test] fn extract_actual_weight_caps_at_pre_weight() { - let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; + let pre = DispatchInfo { + call_weight: Weight::from_parts(1000, 0), + extension_weight: Weight::zero(), + ..Default::default() + }; assert_eq!( extract_actual_weight(&Ok(from_actual_ref_time(Some(1250))), &pre), Weight::from_parts(1000, 0) @@ -887,7 +931,11 @@ mod weight_tests { #[test] fn extract_actual_pays_fee_works() { - let pre = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; + let pre = DispatchInfo { + call_weight: Weight::from_parts(1000, 0), + extension_weight: Weight::zero(), + ..Default::default() + }; assert_eq!(extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(7))), &pre), Pays::Yes); assert_eq!( extract_actual_pays_fee(&Ok(from_actual_ref_time(Some(1000)).into()), &pre), @@ -920,7 +968,8 @@ mod weight_tests { ); let pre = DispatchInfo { - weight: Weight::from_parts(1000, 0), + call_weight: Weight::from_parts(1000, 0), + extension_weight: Weight::zero(), pays_fee: Pays::No, ..Default::default() }; @@ -931,6 +980,26 @@ mod weight_tests { Pays::No ); } + + #[test] + fn weight_accrue_works() { + let mut post_dispatch = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(1100, 25)), + pays_fee: Pays::Yes, + }; + post_dispatch.refund(Weight::from_parts(100, 15)); + assert_eq!( + post_dispatch, + PostDispatchInfo { + actual_weight: Some(Weight::from_parts(1000, 10)), + pays_fee: Pays::Yes + } + ); + + let mut post_dispatch = PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }; + post_dispatch.refund(Weight::from_parts(100, 15)); + assert_eq!(post_dispatch, PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }); + } } #[cfg(test)] @@ -1107,3 +1176,407 @@ mod per_dispatch_class_tests { ); } } + +#[cfg(test)] +mod test_extensions { + use codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::{ + impl_tx_ext_default, + traits::{ + DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf, + TransactionExtension, + }, + transaction_validity::TransactionValidityError, + }; + use sp_weights::Weight; + + use super::{DispatchResult, PostDispatchInfo}; + + /// Test extension that refunds half its cost if the preset inner flag is set. + #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] + pub struct HalfCostIf(pub bool); + + impl TransactionExtension for HalfCostIf { + const IDENTIFIER: &'static str = "HalfCostIf"; + type Implicit = (); + type Val = (); + type Pre = bool; + + fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight { + Weight::from_parts(100, 0) + } + + fn prepare( + self, + _val: Self::Val, + _origin: &DispatchOriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(self.0) + } + + fn post_dispatch_details( + pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + if pre { + Ok(Weight::from_parts(50, 0)) + } else { + Ok(Weight::zero()) + } + } + impl_tx_ext_default!(RuntimeCall; validate); + } + + /// Test extension that refunds its cost if the actual post dispatch weight up until this point + /// in the extension pipeline is less than the preset inner `ref_time` amount. + #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] + pub struct FreeIfUnder(pub u64); + + impl TransactionExtension for FreeIfUnder + where + RuntimeCall: Dispatchable, + { + const IDENTIFIER: &'static str = "FreeIfUnder"; + type Implicit = (); + type Val = (); + type Pre = u64; + + fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight { + Weight::from_parts(200, 0) + } + + fn prepare( + self, + _val: Self::Val, + _origin: &DispatchOriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(self.0) + } + + fn post_dispatch_details( + pre: Self::Pre, + _info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + if let Some(actual) = post_info.actual_weight { + if pre > actual.ref_time() { + return Ok(Weight::from_parts(200, 0)); + } + } + Ok(Weight::zero()) + } + impl_tx_ext_default!(RuntimeCall; validate); + } + + /// Test extension that sets its actual post dispatch `ref_time` weight to the preset inner + /// amount. + #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] + pub struct ActualWeightIs(pub u64); + + impl TransactionExtension for ActualWeightIs { + const IDENTIFIER: &'static str = "ActualWeightIs"; + type Implicit = (); + type Val = (); + type Pre = u64; + + fn weight(&self, _: &RuntimeCall) -> sp_weights::Weight { + Weight::from_parts(300, 0) + } + + fn prepare( + self, + _val: Self::Val, + _origin: &DispatchOriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(self.0) + } + + fn post_dispatch_details( + pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(Weight::from_parts(300u64.saturating_sub(pre), 0)) + } + impl_tx_ext_default!(RuntimeCall; validate); + } +} + +#[cfg(test)] +// Do not complain about unused `dispatch` and `dispatch_aux`. +#[allow(dead_code)] +mod extension_weight_tests { + use crate::assert_ok; + + use super::*; + use sp_core::parameter_types; + use sp_runtime::{ + generic::{self, ExtrinsicFormat}, + traits::{Applyable, BlakeTwo256, DispatchTransaction, TransactionExtension}, + }; + use sp_weights::RuntimeDbWeight; + use test_extensions::{ActualWeightIs, FreeIfUnder, HalfCostIf}; + + use super::weight_tests::frame_system; + use frame_support::construct_runtime; + + pub type TxExtension = (HalfCostIf, FreeIfUnder, ActualWeightIs); + pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + pub type Header = generic::Header; + pub type Block = generic::Block; + pub type AccountId = u64; + pub type Balance = u32; + pub type BlockNumber = u32; + + construct_runtime!( + pub enum ExtRuntime { + System: frame_system, + } + ); + + impl frame_system::Config for ExtRuntime { + type Block = Block; + type AccountId = AccountId; + type Balance = Balance; + type BaseCallFilter = crate::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type DbWeight = DbWeight; + type PalletInfo = PalletInfo; + } + + parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 100, + write: 1000, + }; + } + + pub struct ExtBuilder {} + + impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } + } + + impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut ext = sp_io::TestExternalities::new(Default::default()); + ext.execute_with(|| {}); + ext + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + }) + } + } + + #[test] + fn no_post_dispatch_with_no_refund() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f99 {}); + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1500), ActualWeightIs(0)); + let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone()); + assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0)); + + 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, 0).unwrap(); + let res = call.dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + assert!(post_info.actual_weight.is_none()); + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + assert!(post_info.actual_weight.is_none()); + }); + } + + #[test] + fn no_post_dispatch_refunds_when_dispatched() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f99 {}); + let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(100), ActualWeightIs(0)); + let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone()); + assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0)); + + let mut info = call.get_dispatch_info(); + 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, 0).unwrap().unwrap(); + // 1000 call weight + 50 + 200 + 0 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1250, 0))); + }); + } + + #[test] + fn post_dispatch_with_refunds() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f100 {}); + // First testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0)); + let uxt = UncheckedExtrinsic::new_signed(call.clone(), 0, (), ext.clone()); + assert_eq!(uxt.extension_weight(), Weight::from_parts(600, 0)); + + let mut info = call.get_dispatch_info(); + 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, 0).unwrap(); + let res = call.clone().dispatch(Some(0).into()); + let mut post_info = res.unwrap(); + // 500 actual call weight + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 100 + 0 + 0 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0))); + + // Second testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200)); + 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 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 100 + 200 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0))); + + // Third testcase + let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200)); + 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 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 50 + 0 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0))); + + // Fourth testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300)); + 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 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(500, 0))); + // add the 600 worst case extension weight + post_info.set_extension_weight(&info); + // extension weight should be refunded + assert_ok!(>::post_dispatch( + pre, + &info, + &mut post_info, + 0, + &Ok(()), + )); + // 500 actual call weight + 100 + 200 + 300 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0))); + }); + } + + #[test] + fn checked_extrinsic_apply() { + ExtBuilder::default().build_and_execute(|| { + let call = RuntimeCall::System(frame_system::Call::::f100 {}); + // First testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(2000), ActualWeightIs(0)); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext.clone()), + function: call.clone(), + }; + assert_eq!(xt.extension_weight(), Weight::from_parts(600, 0)); + let mut info = call.get_dispatch_info(); + 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 post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 100 + 0 + 0 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(600, 0))); + + // Second testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(1100), ActualWeightIs(200)); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext), + function: call.clone(), + }; + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 100 + 200 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1000, 0))); + + // Third testcase + let ext: TxExtension = (HalfCostIf(true), FreeIfUnder(1060), ActualWeightIs(200)); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext), + function: call.clone(), + }; + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 50 + 0 + 200 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(750, 0))); + + // Fourth testcase + let ext: TxExtension = (HalfCostIf(false), FreeIfUnder(100), ActualWeightIs(300)); + let xt = CheckedExtrinsic { + format: ExtrinsicFormat::Signed(0, ext), + function: call.clone(), + }; + let post_info = xt.apply::(&info, 0).unwrap().unwrap(); + // 500 actual call weight + 100 + 200 + 300 + assert_eq!(post_info.actual_weight, Some(Weight::from_parts(1100, 0))); + }); + } +} diff --git a/substrate/frame/support/src/generate_genesis_config.rs b/substrate/frame/support/src/generate_genesis_config.rs new file mode 100644 index 000000000000..283840d70c7c --- /dev/null +++ b/substrate/frame/support/src/generate_genesis_config.rs @@ -0,0 +1,1339 @@ +// 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. + +//! Helper macro allowing to construct JSON representation of partially initialized structs. + +use serde_json::Value; +extern crate alloc; +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. +/// +/// Intended to be used in `build_struct_json_patch` macro. +#[derive(Debug)] +pub enum InitilizationType { + /// The field was partially initialized (e.g., specific fields within the struct were set + /// manually). + 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 { + &self.1 + } + + /// Injects a prefix to the field name. + pub fn add_prefix(&mut self, prefix: &str) { + self.1 = format!("{prefix}.{}", self.1).into() + } + + /// Creates new partial field instiance. + pub fn partial(s: &'a str) -> Self { + Self(InitilizationType::Partial, s.into()) + } + + /// Creates new full field instiance. + pub fn full(s: &'a str) -> Self { + Self(InitilizationType::Full, s.into()) + } +} + +impl PartialEq for InitializedField<'_> { + fn eq(&self, other: &String) -> bool { + #[inline] + /// We need to respect the `camelCase` naming for field names. This means that + /// `"camelCaseKey"` should be considered equal to `"camel_case_key"`. This + /// function implements this comparison. + fn compare_keys(ident_chars: core::str::Chars, camel_chars: core::str::Chars) -> bool { + ident_chars + .filter(|c| *c != '_') + .map(|c| c.to_ascii_uppercase()) + .eq(camel_chars.map(|c| c.to_ascii_uppercase())) + } + *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), + } + } +} + +/// Recursively removes keys from provided `json_value` object, retaining only specified keys. +/// +/// This function modifies the provided `json_value` in-place, keeping only the keys listed in +/// `keys_to_retain`. The keys are matched recursively by combining the current key with +/// the `current_root`, allowing for nested field retention. +/// +/// Keys marked as `Full`, are retained as-is. For keys marked as `Partial`, the +/// function recurses into nested objects to retain matching subfields. +/// +/// Function respects the `camelCase` serde_json attribute for structures. This means that +/// `"camelCaseKey"` key will be retained in JSON blob if `"camel_case_key"` exists in +/// `keys_to_retain`. +/// +/// Intended to be used from `build_struct_json_patch` macro. +pub fn retain_initialized_fields( + json_value: &mut Value, + keys_to_retain: &[InitializedField], + current_root: String, +) { + if let serde_json::Value::Object(ref mut map) = json_value { + map.retain(|key, value| { + 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(InitilizationType::Full, _)) => true, + Some(InitializedField(InitilizationType::Partial, _)) => { + retain_initialized_fields(value, keys_to_retain, current_key.clone()); + true + }, + None => false, + } + }) + } +} + +/// Creates a JSON patch for given `struct_type`, supporting recursive field initialization. +/// +/// This macro creates a default `struct_type`, initializing specified fields (which can be nested) +/// with the provided values. Any fields not explicitly given are initialized with their default +/// values. The macro then serializes the fully initialized structure into a JSON blob, retaining +/// only the fields that were explicitly provided, either partially or fully initialized. +/// +/// Using this macro prevents errors from manually creating JSON objects, such as typos or +/// inconsistencies with the `struct_type` structure, by relying on the actual +/// struct definition. This ensures the generated JSON is valid and reflects any future changes +/// to the structure. +/// +/// # Example +/// +/// ```rust +/// use frame_support::build_struct_json_patch; +/// #[derive(Default, serde::Serialize, serde::Deserialize)] +/// #[serde(rename_all = "camelCase")] +/// struct RuntimeGenesisConfig { +/// a_field: u32, +/// b_field: B, +/// c_field: u32, +/// } +/// +/// #[derive(Default, serde::Serialize, serde::Deserialize)] +/// #[serde(rename_all = "camelCase")] +/// struct B { +/// i_field: u32, +/// j_field: u32, +/// } +/// impl B { +/// fn new() -> Self { +/// Self { i_field: 0, j_field: 2 } +/// } +/// } +/// +/// assert_eq!( +/// build_struct_json_patch! ( RuntimeGenesisConfig { +/// a_field: 66, +/// }), +/// serde_json::json!({ +/// "aField": 66, +/// }) +/// ); +/// +/// assert_eq!( +/// build_struct_json_patch! ( RuntimeGenesisConfig { +/// //"partial" initialization of `b_field` +/// b_field: B { +/// i_field: 2, +/// } +/// }), +/// serde_json::json!({ +/// "bField": {"iField": 2} +/// }) +/// ); +/// +/// assert_eq!( +/// build_struct_json_patch! ( RuntimeGenesisConfig { +/// a_field: 66, +/// //"full" initialization of `b_field` +/// b_field: B::new() +/// }), +/// serde_json::json!({ +/// "aField": 66, +/// "bField": {"iField": 0, "jField": 2} +/// }) +/// ); +/// ``` +/// +/// In this example: +/// ```ignore +/// build_struct_json_patch! ( RuntimeGenesisConfig { +/// b_field: B { +/// i_field: 2, +/// } +/// }), +/// ``` +/// `b_field` is partially initialized, it will be expanded to: +/// ```ignore +/// RuntimeGenesisConfig { +/// b_field { +/// i_field: 2, +/// ..Default::default() +/// }, +/// ..Default::default() +/// } +/// ``` +/// While all other fields are initialized with default values. The macro serializes this, retaining +/// only the provided fields. +#[macro_export] +macro_rules! build_struct_json_patch { + ( + $($struct_type:ident)::+ { $($body:tt)* } + ) => { + { + 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 @ { $($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 @ { $($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)::+ { $($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() + }, + $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: $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: $value:expr ) => { + ( + $($struct_type)::+ { + $key: { + $all_keys.push($crate::generate_genesis_config::InitializedField::full(stringify!($key))); + $value + }, + ..Default::default() + }, + $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 ) => { + ( + $($struct_type)::+ { + $key: { + $all_keys.push($crate::generate_genesis_config::InitializedField::full(stringify!($key))); + $key + }, + ..Default::default() + }, + $crate::generate_genesis_config::InitilizationType::Partial + ) + }; + // update struct + ($($struct_type:ident)::+, $all_keys:ident @ ..$update:expr ) => { + ( + $($struct_type)::+ { + ..$update + }, + $crate::generate_genesis_config::InitilizationType::Full + ) + }; + ($($struct_type:ident)::+, $all_keys:ident @ $(,)?) => { + ( + $($struct_type)::+ { + ..Default::default() + }, + $crate::generate_genesis_config::InitilizationType::Partial + ) + }; +} + +#[cfg(test)] +mod test { + mod nested_mod { + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + pub struct InsideMod { + pub a: u32, + pub b: u32, + } + + pub mod nested_mod2 { + pub mod nested_mod3 { + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + pub struct InsideMod3 { + pub a: u32, + pub b: u32, + pub s: super::super::InsideMod, + } + } + } + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct TestStruct { + a: u32, + b: u32, + s: S, + s3: S3, + t3: S3, + i: Nested1, + e: E, + t: nested_mod::InsideMod, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3, + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct S { + x: u32, + } + + impl S { + fn new(c: u32) -> Self { + Self { x: c } + } + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct E(u8); + + #[derive(Default, Debug, serde::Serialize, serde::Deserialize)] + enum SomeEnum { + #[default] + A, + B(T), + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct S3 { + x: u32, + y: u32, + z: u32, + } + + impl S3 { + fn new(c: u32) -> Self { + Self { x: c, y: c, z: c } + } + + fn new_from_s(s: S) -> Self { + Self { x: s.x, ..Default::default() } + } + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct Nested3 { + a: u32, + b: u32, + s: S, + v: Vec<(u32, u32, u32, SomeEnum)>, + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct Nested2 { + a: u32, + iii: Nested3, + v: Vec, + s3: S3, + } + + impl Nested2 { + fn new(a: u32) -> Self { + Nested2 { + a, + v: vec![a, a, a], + iii: Nested3 { a, b: a, ..Default::default() }, + s3: S3 { x: a, ..Default::default() }, + } + } + } + + #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] + struct Nested1 { + a: u32, + ii: Nested2, + } + + macro_rules! test { + ($($struct:ident)::+ { $($v:tt)* }, { $($j:tt)* } ) => {{ + let expected = serde_json::json!({ $($j)* }); + let value = build_struct_json_patch!($($struct)::+ { $($v)* }); + assert_eq!(value, expected); + }}; + } + + #[test] + fn test_generate_config_macro() { + 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 }); + } + test!(TestStruct { s: S { x: 5 } }, { "s": { "x": 5 } }); + test!( + TestStruct { s: S::new(C) }, + { + "s": { "x": 5 } + } + ); + test!( + TestStruct { s: S { x: t } }, + { + "s": { "x": t } + } + ); + test!( + TestStruct { + b: 5, + s: S { x: t } + }, + { + "b": 5, + "s": { "x": 5 } + } + ); + test!( + TestStruct { s: S::new(C), b: 5 }, + { + "s": { "x": 5 }, "b": 5 + } + ); + test!( + TestStruct { s3: S3 { x: t } }, + { + "s3": { "x": 5 } + } + ); + test!( + TestStruct { + s3: S3 { x: t, y: 2 } + }, + { + "s3": { "x": 5, "y": 2 } + } + ); + // // + test!( + TestStruct { + s3: S3 { x: t, y: 2 }, + t3: S3 { x: 2 } + }, + { + "s3": { "x": t, "y": 2 }, + "t3": { "x": 2 } + } + + ); + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { iii: Nested3 { a: 2 } } + } + } + , + { + "i": { + "ii": { "iii": { "a": 2 } } + } + } + + ); + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { + iii: Nested3 { a: 2, s: S::new(C) } + } + } + }, + { + "i": { + "ii": { + "iii": { "a": 2, "s": { "x": 5} } + } + } + } + ); + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { + iii: Nested3 { s: S::new(C), a: 2 } + }, + a: 44 + }, + a: 3, + s3: S3 { x: 5 }, + b: 4 + }, + { + "i": { + "ii": { + "iii": { "a": 2, "s": { "x": 5} } + }, + "a": 44 + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + test!( + TestStruct { + i: Nested1 { + ii: Nested2::new(66), + a: 44, + }, + a: 3, + s3: S3 { x: 5 }, + b: 4 + }, + { + "i": { + "ii": { + "a": 66, + "s3": { "x":66, "y": 0, "z": 0 }, + "iii": { "a": 66,"b":66, "s": { "x": 0 }, "v": Vec::::default() }, + "v": vec![66,66,66] + }, + "a": 44 + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { + a: 66, + s3: S3 { x: 66 }, + iii: Nested3 { + a: 66,b:66 + }, + v: vec![66,66,66] + }, + a: 44, + }, + a: 3, + s3: S3 { x: 5 }, + b: 4 + }, + { + "i": { + "ii": { + "a": 66, + "s3": { "x":66, }, + "iii": { "a": 66,"b":66, }, + "v": vec![66,66,66] + }, + "a": 44 + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { + iii: Nested3 { a: 2, s: S::new(C) }, + }, + a: 44, + }, + a: 3, + s3: S3 { x: 5 }, + b: 4, + }, + { + "i": { + "ii": { + "iii": { "a": 2, "s": { "x": 5 } }, + }, + "a" : 44, + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { + s3: S3::new(5), + iii: Nested3 { a: 2, s: S::new(C) }, + }, + a: 44, + }, + a: 3, + s3: S3 { x: 5 }, + b: 4, + }, + { + "i": { + "ii": { + "iii": { "a": 2, "s": { "x": 5 } }, + "s3": {"x": 5, "y": 5, "z": 5 } + }, + "a" : 44, + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + test!( + TestStruct { + a: 3, + s3: S3 { x: 5 }, + b: 4, + i: Nested1 { + ii: Nested2 { + iii: Nested3 { a: 2, s: S::new(C) }, + s3: S3::new_from_s(S { x: 4 }) + }, + a: 44, + } + }, + { + "i": { + "ii": { + "iii": { "a": 2, "s": { "x": 5 } }, + "s3": {"x": 4, "y": 0, "z": 0 } + }, + "a" : 44, + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + let i = [0u32, 1u32, 2u32]; + test!( + TestStruct { + i: Nested1 { + ii: Nested2 { + iii: Nested3 { + a: 2, + s: S::new(C), + v: i.iter() + .map(|x| (*x, 2 * x, 100 + x, SomeEnum::::A)) + .collect::>(), + }, + s3: S3::new_from_s(S { x: 4 }) + }, + a: 44, + }, + a: 3, + s3: S3 { x: 5 }, + b: 4, + }, + + { + "i": { + "ii": { + "iii": { + "a": 2, + "s": { "x": 5 }, + "v": i.iter() + .map(|x| (*x, 2 * x, 100 + x, SomeEnum::::A)) + .collect::>(), + }, + "s3": {"x": 4, "y": 0, "z": 0 } + }, + "a" : 44, + }, + "a": 3, + "s3": { "x": 5 }, + "b": 4 + } + ); + } + + #[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!( + TestStruct { t: nested_mod::InsideMod { a: 32 } }, + { + "t" : { "a": 32 } + } + ); + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { a: 32 } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32 } + } + ); + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3 { + a: 32, + s: nested_mod::InsideMod { a: 34 }, + } + }, + { + "t" : { "a": 32 }, + "u" : { "a": 32, "s": { "a": 34 } } + } + ); + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3::default() + }, + { + "t" : { "a": 32 }, + "u" : { "a": 0, "b": 0, "s": { "a": 0, "b": 0} } + } + ); + + let i = [0u32, 1u32, 2u32]; + const C: u32 = 5; + test!( + TestStruct { + t: nested_mod::InsideMod { a: 32 }, + u: nested_mod::nested_mod2::nested_mod3::InsideMod3::default(), + i: Nested1 { + ii: Nested2 { + iii: Nested3 { + a: 2, + s: S::new(C), + v: i.iter() + .map(|x| (*x, 2 * x, 100 + x, SomeEnum::::A)) + .collect::>(), + }, + s3: S3::new_from_s(S { x: 4 }) + }, + a: 44, + }, + }, + { + "t" : { "a": 32 }, + "u" : { "a": 0, "b": 0, "s": { "a": 0, "b": 0} } , + "i": { + "ii": { + "iii": { + "a": 2, + "s": { "x": 5 }, + "v": i.iter() + .map(|x| (*x, 2 * x, 100 + x, SomeEnum::::A)) + .collect::>(), + }, + "s3": {"x": 4, "y": 0, "z": 0 } + }, + "a" : 44, + }, + } + ); + } +} + +#[cfg(test)] +mod retain_keys_test { + use super::*; + use serde_json::json; + + macro_rules! check_initialized_field_eq_cc( + ( $s:literal ) => { + let field = InitializedField::full($s); + let cc = inflector::cases::camelcase::to_camel_case($s); + assert_eq!(field,cc); + } ; + ( &[ $f:literal $(, $r:literal)* ]) => { + let field = InitializedField::full( + concat!( $f $(,".",$r)+ ) + ); + let cc = [ $f $(,$r)+ ].into_iter() + .map(|s| inflector::cases::camelcase::to_camel_case(s)) + .collect::>() + .join("."); + assert_eq!(field,cc); + } ; + ); + + #[test] + fn test_initialized_field_eq_cc_string() { + check_initialized_field_eq_cc!("a_"); + check_initialized_field_eq_cc!("abc"); + check_initialized_field_eq_cc!("aBc"); + check_initialized_field_eq_cc!("aBC"); + check_initialized_field_eq_cc!("ABC"); + check_initialized_field_eq_cc!("2abs"); + check_initialized_field_eq_cc!("2Abs"); + check_initialized_field_eq_cc!("2ABs"); + check_initialized_field_eq_cc!("2aBs"); + check_initialized_field_eq_cc!("AlreadyCamelCase"); + check_initialized_field_eq_cc!("alreadyCamelCase"); + check_initialized_field_eq_cc!("C"); + check_initialized_field_eq_cc!("1a"); + check_initialized_field_eq_cc!("_1a"); + check_initialized_field_eq_cc!("a_b"); + check_initialized_field_eq_cc!("_a_b"); + check_initialized_field_eq_cc!("a___b"); + check_initialized_field_eq_cc!("__a_b"); + check_initialized_field_eq_cc!("_a___b_C"); + check_initialized_field_eq_cc!("__A___B_C"); + check_initialized_field_eq_cc!(&["a_b", "b_c"]); + check_initialized_field_eq_cc!(&["al_pha", "_a___b_C"]); + check_initialized_field_eq_cc!(&["al_pha_", "_a___b_C"]); + check_initialized_field_eq_cc!(&["first_field", "al_pha_", "_a___b_C"]); + check_initialized_field_eq_cc!(&["al_pha_", "__2nd_field", "_a___b_C"]); + check_initialized_field_eq_cc!(&["al_pha_", "__2nd3and_field", "_a___b_C"]); + check_initialized_field_eq_cc!(&["_a1", "_a2", "_a3_"]); + } + + #[test] + fn test01() { + let mut v = json!({ + "a":1 + }); + let e = v.clone(); + retain_initialized_fields(&mut v, &[InitializedField::full("a")], String::default()); + assert_eq!(e, v); + } + + #[test] + fn test02() { + let mut v = json!({ + "a":1 + }); + retain_initialized_fields(&mut v, &[InitializedField::full("b")], String::default()); + assert_eq!(Value::Object(Default::default()), v); + } + + #[test] + fn test03() { + let mut v = json!({}); + retain_initialized_fields(&mut v, &[], String::default()); + assert_eq!(Value::Object(Default::default()), v); + } + + #[test] + fn test04() { + let mut v = json!({}); + retain_initialized_fields(&mut v, &[InitializedField::full("b")], String::default()); + assert_eq!(Value::Object(Default::default()), v); + } + + #[test] + fn test05() { + let mut v = json!({ + "a":1 + }); + retain_initialized_fields(&mut v, &[], String::default()); + assert_eq!(Value::Object(Default::default()), v); + } + + #[test] + fn test06() { + let mut v = json!({ + "a": { + "b":1, + "c":2 + } + }); + retain_initialized_fields(&mut v, &[], String::default()); + assert_eq!(Value::Object(Default::default()), v); + } + + #[test] + fn test07() { + let mut v = json!({ + "a": { + "b":1, + "c":2 + } + }); + retain_initialized_fields(&mut v, &[InitializedField::full("a.b")], String::default()); + assert_eq!(Value::Object(Default::default()), v); + } + + #[test] + fn test08() { + let mut v = json!({ + "a": { + "b":1, + "c":2 + } + }); + let e = json!({ + "a": { + "b":1, + } + }); + retain_initialized_fields( + &mut v, + &[InitializedField::partial("a"), InitializedField::full("a.b")], + String::default(), + ); + assert_eq!(e, v); + } + + #[test] + fn test09() { + let mut v = json!({ + "a": { + "b":1, + "c":2 + } + }); + let e = json!({ + "a": { + "b":1, + "c":2, + } + }); + retain_initialized_fields(&mut v, &[InitializedField::full("a")], String::default()); + assert_eq!(e, v); + } +} 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 269867e38c51..c64987b17d35 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -53,6 +53,7 @@ pub mod __private { pub use paste; pub use scale_info; pub use serde; + pub use serde_json; pub use sp_core::{Get, OpaqueMetadata, Void}; pub use sp_crypto_hashing_proc_macro; pub use sp_inherents; @@ -63,7 +64,8 @@ pub mod __private { #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; pub use sp_runtime::{ - traits::Dispatchable, DispatchError, RuntimeDebug, StateVersion, TransactionOutcome, + traits::{AsSystemOriginSigner, AsTransactionAuthorizedOrigin, Dispatchable}, + DispatchError, RuntimeDebug, StateVersion, TransactionOutcome, }; #[cfg(feature = "std")] pub use sp_state_machine::BasicExternalities; @@ -902,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, @@ -915,7 +918,10 @@ pub mod pallet_prelude { pub use scale_info::TypeInfo; pub use sp_inherents::MakeFatalError; pub use sp_runtime::{ - traits::{MaybeSerializeDeserialize, Member, ValidateUnsigned}, + traits::{ + CheckedAdd, CheckedConversion, CheckedDiv, CheckedMul, CheckedShl, CheckedShr, + CheckedSub, MaybeSerializeDeserialize, Member, One, ValidateUnsigned, Zero, + }, transaction_validity::{ InvalidTransaction, TransactionLongevity, TransactionPriority, TransactionSource, TransactionTag, TransactionValidity, TransactionValidityError, UnknownTransaction, @@ -1562,6 +1568,53 @@ pub mod pallet_macros { /// * [`frame_support::derive_impl`]. /// * [`#[pallet::no_default]`](`no_default`) /// * [`#[pallet::no_default_bounds]`](`no_default_bounds`) + /// + /// ## Optional: `without_automatic_metadata` + /// + /// By default, the associated types of the `Config` trait that require the `TypeInfo` or + /// `Parameter` bounds are included in the metadata of the pallet. + /// + /// The optional `without_automatic_metadata` argument can be used to exclude these + /// associated types from the metadata collection. + /// + /// Furthermore, the `without_automatic_metadata` argument can be used in combination with + /// the [`#[pallet::include_metadata]`](`include_metadata`) attribute to selectively + /// include only certain associated types in the metadata collection. + /// + /// ``` + /// #[frame_support::pallet] + /// mod pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # use core::fmt::Debug; + /// # use frame_support::traits::Contains; + /// # + /// # pub trait SomeMoreComplexBound {} + /// # + /// #[pallet::pallet] + /// pub struct Pallet(_); + /// + /// #[pallet::config(with_default, without_automatic_metadata)] // <- with_default and without_automatic_metadata are optional + /// pub trait Config: frame_system::Config { + /// /// The overarching event type. + /// #[pallet::no_default_bounds] // Default with bounds is not supported for RuntimeEvent + /// type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// + /// /// A simple type. + /// // Type that would have been included in metadata, but is now excluded. + /// type SimpleType: From + TypeInfo; + /// + /// // The `pallet::include_metadata` is used to selectively include this type in metadata. + /// #[pallet::include_metadata] + /// type SelectivelyInclude: From + TypeInfo; + /// } + /// + /// #[pallet::event] + /// pub enum Event { + /// SomeEvent(u16, u32), + /// } + /// } + /// ``` pub use frame_support_procedural::config; /// Allows defining an enum that gets composed as an aggregate enum by `construct_runtime`. @@ -1645,8 +1698,8 @@ pub mod pallet_macros { /// [`ValidateUnsigned`](frame_support::pallet_prelude::ValidateUnsigned) for /// type `Pallet`, and some optional where clause. /// - /// NOTE: There is also the [`sp_runtime::traits::SignedExtension`] trait that can be used - /// to add some specific logic for transaction validation. + /// NOTE: There is also the [`sp_runtime::traits::TransactionExtension`] trait that can be + /// used to add some specific logic for transaction validation. /// /// ## Macro expansion /// @@ -1830,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 @@ -1959,6 +2017,17 @@ pub mod pallet_macros { /// will be returned. pub use frame_support_procedural::event; + /// Selectively includes associated types in the metadata. + /// + /// The optional attribute allows you to selectively include associated types in the + /// metadata. This can be attached to trait items that implement `TypeInfo`. + /// + /// By default all collectable associated types are included in the metadata. + /// + /// This attribute can be used in combination with the + /// [`#[pallet::config(without_automatic_metadata)]`](`config`). + pub use frame_support_procedural::include_metadata; + /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. /// /// In slightly simplified terms, this macro declares the set of "transactions" of a @@ -2526,9 +2595,12 @@ sp_core::generate_feature_enabled_macro!(try_runtime_enabled, feature = "try-run sp_core::generate_feature_enabled_macro!(try_runtime_or_std_enabled, any(feature = "try-runtime", feature = "std"), $); sp_core::generate_feature_enabled_macro!(try_runtime_and_std_not_enabled, all(not(feature = "try-runtime"), not(feature = "std")), $); -// Helper for implementing GenesisBuilder runtime API +/// Helper for implementing GenesisBuilder runtime API pub mod genesis_builder_helper; +/// Helper for generating the `RuntimeGenesisConfig` instance for presets. +pub mod generate_genesis_config; + #[cfg(test)] mod test { // use super::*; diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 905d6143e4f1..3fdf8d6edc95 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -825,14 +825,14 @@ impl SteppedMigrations for T { fn nth_id(n: u32) -> Option> { n.is_zero() - .then_some(T::id().encode()) + .then(|| T::id().encode()) .defensive_proof("nth_id should only be called with n==0") } fn nth_max_steps(n: u32) -> Option> { // It should be generally fine to call with n>0, but the code should not attempt to. n.is_zero() - .then_some(T::max_steps()) + .then(|| T::max_steps()) .defensive_proof("nth_max_steps should only be called with n==0") } diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 6e59ff9d030b..728426cc84c7 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -23,7 +23,8 @@ pub mod tokens; pub use tokens::{ currency::{ ActiveIssuanceOf, Currency, InspectLockableCurrency, LockIdentifier, LockableCurrency, - NamedReservableCurrency, ReservableCurrency, TotalIssuanceOf, VestingSchedule, + NamedReservableCurrency, ReservableCurrency, TotalIssuanceOf, VestedTransfer, + VestingSchedule, }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, @@ -56,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, IsInherent, - IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, - SameOrOther, 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}; @@ -109,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/dispatch.rs b/substrate/frame/support/src/traits/dispatch.rs index 7dc8d3e4f5a6..dbdf0885dd24 100644 --- a/substrate/frame/support/src/traits/dispatch.rs +++ b/substrate/frame/support/src/traits/dispatch.rs @@ -482,7 +482,7 @@ pub trait OriginTrait: Sized { type Call; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: Into + CallerTrait + MaxEncodedLen; + type PalletsOrigin: Send + Sync + Into + CallerTrait + MaxEncodedLen; /// The AccountId used across the system. type AccountId; @@ -496,6 +496,14 @@ pub trait OriginTrait: Sized { /// Replace the caller with caller from the other origin fn set_caller_from(&mut self, other: impl Into); + /// Replace the caller with caller from the other origin + fn set_caller(&mut self, caller: Self::PalletsOrigin); + + /// Replace the caller with caller from the other origin + fn set_caller_from_signed(&mut self, caller_account: Self::AccountId) { + self.set_caller(Self::PalletsOrigin::from(RawOrigin::Signed(caller_account))) + } + /// Filter the call if caller is not root, if false is returned then the call must be filtered /// out. /// @@ -544,6 +552,17 @@ pub trait OriginTrait: Sized { fn as_system_ref(&self) -> Option<&RawOrigin> { self.caller().as_system_ref() } + + /// Extract a reference to the signer, if that's what the caller is. + fn as_signer(&self) -> Option<&Self::AccountId> { + self.caller().as_system_ref().and_then(|s| { + if let RawOrigin::Signed(ref who) = s { + Some(who) + } else { + None + } + }) + } } #[cfg(test)] diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 4d3b122daf67..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}; @@ -919,32 +919,82 @@ pub trait IsInherent { } /// An extrinsic on which we can get access to call. -pub trait ExtrinsicCall: sp_runtime::traits::Extrinsic { +pub trait ExtrinsicCall: sp_runtime::traits::ExtrinsicLike { + type Call; + /// Get the call of the extrinsic. fn call(&self) -> &Self::Call; } -#[cfg(feature = "std")] -impl ExtrinsicCall for sp_runtime::testing::TestXt +impl ExtrinsicCall + for sp_runtime::generic::UncheckedExtrinsic where - Call: codec::Codec + Sync + Send + TypeInfo, + Address: TypeInfo, + Call: TypeInfo, + Signature: TypeInfo, Extra: TypeInfo, { - fn call(&self) -> &Self::Call { - &self.call + type Call = Call; + + fn call(&self) -> &Call { + &self.function } } -impl ExtrinsicCall +/// Interface for types capable of constructing an inherent extrinsic. +pub trait InherentBuilder: ExtrinsicCall { + /// Create a new inherent from a given call. + fn new_inherent(call: Self::Call) -> Self; +} + +impl InherentBuilder for sp_runtime::generic::UncheckedExtrinsic where Address: TypeInfo, Call: TypeInfo, Signature: TypeInfo, - Extra: sp_runtime::traits::SignedExtension + TypeInfo, + Extra: TypeInfo, { - fn call(&self) -> &Self::Call { - &self.function + fn new_inherent(call: Self::Call) -> Self { + Self::new_bare(call) + } +} + +/// Interface for types capable of constructing a signed transaction. +pub trait SignedTransactionBuilder: ExtrinsicCall { + type Address; + type Signature; + type Extension; + + /// Create a new signed transaction from a given call and extension using the provided signature + /// data. + fn new_signed_transaction( + call: Self::Call, + signed: Self::Address, + signature: Self::Signature, + tx_ext: Self::Extension, + ) -> Self; +} + +impl SignedTransactionBuilder + for sp_runtime::generic::UncheckedExtrinsic +where + Address: TypeInfo, + Call: TypeInfo, + Signature: TypeInfo, + Extension: TypeInfo, +{ + type Address = Address; + type Signature = Signature; + type Extension = Extension; + + fn new_signed_transaction( + call: Self::Call, + signed: Address, + signature: Signature, + tx_ext: Extension, + ) -> Self { + Self::new_signed(call, signed, signature, tx_ext) } } diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index b3db4c98001d..ea2c66a32cb0 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -30,7 +30,9 @@ use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError}; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; mod lockable; -pub use lockable::{InspectLockableCurrency, LockIdentifier, LockableCurrency, VestingSchedule}; +pub use lockable::{ + InspectLockableCurrency, LockIdentifier, LockableCurrency, VestedTransfer, VestingSchedule, +}; /// Abstraction over a fungible assets system. pub trait Currency { diff --git a/substrate/frame/support/src/traits/tokens/currency/lockable.rs b/substrate/frame/support/src/traits/tokens/currency/lockable.rs index 51a48dd15ce8..4ec45c908e68 100644 --- a/substrate/frame/support/src/traits/tokens/currency/lockable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/lockable.rs @@ -112,3 +112,56 @@ pub trait VestingSchedule { /// NOTE: This doesn't alter the free balance of the account. fn remove_vesting_schedule(who: &AccountId, schedule_index: u32) -> DispatchResult; } + +/// A vested transfer over a currency. This allows a transferred amount to vest over time. +pub trait VestedTransfer { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// The currency that this schedule applies to. + type Currency: Currency; + + /// Execute a vested transfer from `source` to `target` with the given schedule: + /// - `locked`: The amount to be transferred and for the vesting schedule to apply to. + /// - `per_block`: The amount to be unlocked each block. (linear vesting) + /// - `starting_block`: The block where the vesting should start. This block can be in the past + /// or future, and should adjust when the tokens become available to the user. + /// + /// Example: Assume we are on block 100. If `locked` amount is 100, and `per_block` is 1: + /// - If `starting_block` is 0, then the whole 100 tokens will be available right away as the + /// vesting schedule started in the past and has fully completed. + /// - If `starting_block` is 50, then 50 tokens are made available right away, and 50 more + /// tokens will unlock one token at a time until block 150. + /// - If `starting_block` is 100, then each block, 1 token will be unlocked until the whole + /// balance is unlocked at block 200. + /// - If `starting_block` is 200, then the 100 token balance will be completely locked until + /// block 200, and then start to unlock one token at a time until block 300. + fn vested_transfer( + source: &AccountId, + target: &AccountId, + locked: >::Balance, + per_block: >::Balance, + starting_block: Self::Moment, + ) -> DispatchResult; +} + +// An no-op implementation of `VestedTransfer` for pallets that require this trait, but users may +// not want to implement this functionality +pub struct NoVestedTransfers { + phantom: core::marker::PhantomData, +} + +impl> VestedTransfer for NoVestedTransfers { + type Moment = (); + type Currency = C; + + fn vested_transfer( + _source: &AccountId, + _target: &AccountId, + _locked: >::Balance, + _per_block: >::Balance, + _starting_block: Self::Moment, + ) -> DispatchResult { + Err(sp_runtime::DispatchError::Unavailable.into()) + } +} 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 5c12c082305f..2187ee22b395 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -59,10 +59,7 @@ std = [ "sp-version/std", "test-pallet/std", ] -experimental = [ - "frame-support/experimental", - "frame-system/experimental", -] +experimental = ["frame-support/experimental", "frame-system/experimental"] try-runtime = [ "frame-executive/try-runtime", "frame-support/try-runtime", 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/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index 59e36775d464..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 @@ -711,6 +711,31 @@ note: the trait `Config` must be implemented | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0599]: the function or associated item `pallet_associated_types_metadata` exists for struct `Pallet`, but its trait bounds were not satisfied + --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 + | +20 | construct_runtime! { + | __^ + | | _| + | || +21 | || pub struct Runtime where + | ||______________________- doesn't satisfy `Runtime: Config` +22 | | Block = Block, +23 | | NodeBlock = Block, +... | +27 | | } +28 | | } + | |__^ function or associated item cannot be called on `Pallet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Runtime: Config` +note: the trait `Config` must be implemented + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | pub trait Config: 'static + Eq + Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `frame_support::construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0277]: the trait bound `Runtime: Config` is not satisfied --> tests/construct_runtime_ui/deprecated_where_block.rs:20:1 | @@ -726,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/construct_runtime_ui/undefined_inherent_part.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index d8dc7bd45bc6..9608fa58e3c9 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -32,8 +32,9 @@ error[E0599]: no function or associated item named `create_inherent` found for s | |_^ function or associated item not found in `Pallet` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `create_inherent`, perhaps you need to implement it: - candidate #1: `ProvideInherent` + = note: the following traits define an item `create_inherent`, perhaps you need to implement one of them: + candidate #1: `CreateInherent` + candidate #2: `ProvideInherent` = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `is_inherent` found for struct `pallet::Pallet` in the current scope diff --git a/substrate/frame/support/test/tests/enum_deprecation.rs b/substrate/frame/support/test/tests/enum_deprecation.rs index ed9b2b5a735d..c1167dfe339c 100644 --- a/substrate/frame/support/test/tests/enum_deprecation.rs +++ b/substrate/frame/support/test/tests/enum_deprecation.rs @@ -132,8 +132,12 @@ impl pallet::Config for Runtime { pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = - sp_runtime::testing::TestXt>; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic< + u64, + RuntimeCall, + sp_runtime::testing::UintAuthorityId, + frame_system::CheckNonZeroSender, +>; frame_support::construct_runtime!( pub struct Runtime { diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index 3d6aa1d83749..b0b83f772499 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -27,19 +27,21 @@ use frame_support::{ storage::{unhashed, unhashed::contains_prefixed_key}, traits::{ ConstU32, GetCallIndex, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, - OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, - UnfilteredDispatchable, + OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, SignedTransactionBuilder, + StorageVersion, UnfilteredDispatchable, }, weights::{RuntimeDbWeight, Weight}, OrdNoBound, PartialOrdNoBound, }; +use frame_system::offchain::{CreateSignedTransaction, CreateTransactionBase, SigningTypes}; use scale_info::{meta_type, TypeInfo}; use sp_io::{ hashing::{blake2_128, twox_128, twox_64}, TestExternalities, }; use sp_runtime::{ - traits::{Dispatchable, Extrinsic as ExtrinsicT, SignaturePayload as SignaturePayloadT}, + testing::UintAuthorityId, + traits::{Block as BlockT, Dispatchable}, DispatchError, ModuleError, }; @@ -751,8 +753,51 @@ impl pallet5::Config for Runtime { pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = - sp_runtime::testing::TestXt>; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic< + u64, + RuntimeCall, + UintAuthorityId, + frame_system::CheckNonZeroSender, +>; +pub type UncheckedSignaturePayload = sp_runtime::generic::UncheckedSignaturePayload< + u64, + UintAuthorityId, + frame_system::CheckNonZeroSender, +>; + +impl SigningTypes for Runtime { + type Public = UintAuthorityId; + type Signature = UintAuthorityId; +} + +impl CreateTransactionBase for Runtime +where + RuntimeCall: From, +{ + type RuntimeCall = RuntimeCall; + type Extrinsic = UncheckedExtrinsic; +} + +impl CreateSignedTransaction for Runtime +where + RuntimeCall: From, +{ + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( + call: RuntimeCall, + _public: UintAuthorityId, + account: u64, + nonce: u64, + ) -> Option { + Some(UncheckedExtrinsic::new_signed( + call, + nonce, + account.into(), + frame_system::CheckNonZeroSender::new(), + )) + } +} frame_support::construct_runtime!( pub struct Runtime { @@ -814,7 +859,8 @@ fn call_expand() { assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { - weight: frame_support::weights::Weight::from_parts(3, 0), + call_weight: frame_support::weights::Weight::from_parts(3, 0), + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes } @@ -902,10 +948,8 @@ fn inherent_expand() { let inherents = InherentData::new().create_extrinsics(); - let expected = vec![UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - signature: None, - }]; + let expected = + vec![UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {}))]; assert_eq!(expected, inherents); let block = Block::new( @@ -917,14 +961,11 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - signature: None, - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), - signature: None, - }, + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { + foo: 1, + bar: 0, + })), ], ); @@ -939,14 +980,11 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - signature: None, - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo { foo: 0, bar: 0 }), - signature: None, - }, + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { + foo: 0, + bar: 0, + })), ], ); @@ -960,10 +998,9 @@ fn inherent_expand() { BlakeTwo256::hash(b"test"), Digest::default(), ), - vec![UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), - signature: None, - }], + vec![UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_storage_layer { + foo: 0, + }))], ); let mut inherent = InherentData::new(); @@ -978,10 +1015,12 @@ fn inherent_expand() { BlakeTwo256::hash(b"test"), Digest::default(), ), - vec![UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - signature: Some((1, Default::default())), - }], + vec![UncheckedExtrinsic::new_signed( + RuntimeCall::Example(pallet::Call::foo_no_post_info {}), + 1, + 1.into(), + Default::default(), + )], ); let mut inherent = InherentData::new(); @@ -997,14 +1036,13 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), - signature: None, - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), - signature: None, - }, + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { + foo: 1, + bar: 1, + })), + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_storage_layer { + foo: 0, + })), ], ); @@ -1019,18 +1057,14 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), - signature: None, - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), - signature: None, - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - signature: None, - }, + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { + foo: 1, + bar: 1, + })), + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_storage_layer { + foo: 0, + })), + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), ], ); @@ -1045,18 +1079,17 @@ fn inherent_expand() { Digest::default(), ), vec![ - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), - signature: None, - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), - signature: Some((1, Default::default())), - }, - UncheckedExtrinsic { - call: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), - signature: None, - }, + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo { + foo: 1, + bar: 1, + })), + UncheckedExtrinsic::new_signed( + RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), + 1, + 1.into(), + Default::default(), + ), + UncheckedExtrinsic::new_bare(RuntimeCall::Example(pallet::Call::foo_no_post_info {})), ], ); @@ -1838,18 +1871,22 @@ fn metadata() { } let extrinsic = ExtrinsicMetadata { - version: 4, + version: 5, signed_extensions: vec![SignedExtensionMetadata { identifier: "UnitSignedExtension", ty: meta_type::<()>(), additional_signed: meta_type::<()>(), }], - address_ty: meta_type::<<::SignaturePayload as SignaturePayloadT>::SignatureAddress>(), - call_ty: meta_type::<::Call>(), + address_ty: meta_type::< + <<::Block as BlockT>::Extrinsic as SignedTransactionBuilder>::Address + >(), + call_ty: meta_type::<>::RuntimeCall>(), signature_ty: meta_type::< - <::SignaturePayload as SignaturePayloadT>::Signature + <<::Block as BlockT>::Extrinsic as SignedTransactionBuilder>::Signature + >(), + extra_ty: meta_type::< + <<::Block as BlockT>::Extrinsic as SignedTransactionBuilder>::Extension >(), - extra_ty: meta_type::<<::SignaturePayload as SignaturePayloadT>::SignatureExtra>(), }; let outer_enums = OuterEnums { @@ -1929,21 +1966,28 @@ fn metadata_ir_pallet_runtime_docs() { fn extrinsic_metadata_ir_types() { let ir = Runtime::metadata_ir().extrinsic; - assert_eq!(meta_type::<<::SignaturePayload as SignaturePayloadT>::SignatureAddress>(), ir.address_ty); + assert_eq!( + meta_type::<<<::Block as BlockT>::Extrinsic as SignedTransactionBuilder>::Address>(), + ir.address_ty + ); assert_eq!(meta_type::(), ir.address_ty); - assert_eq!(meta_type::<::Call>(), ir.call_ty); + assert_eq!( + meta_type::<>::RuntimeCall>(), + ir.call_ty + ); assert_eq!(meta_type::(), ir.call_ty); assert_eq!( - meta_type::< - <::SignaturePayload as SignaturePayloadT>::Signature, - >(), + meta_type::<<<::Block as BlockT>::Extrinsic as SignedTransactionBuilder>::Signature>(), ir.signature_ty ); - assert_eq!(meta_type::<()>(), ir.signature_ty); + assert_eq!(meta_type::(), ir.signature_ty); - assert_eq!(meta_type::<<::SignaturePayload as SignaturePayloadT>::SignatureExtra>(), ir.extra_ty); + assert_eq!( + meta_type::<<<::Block as BlockT>::Extrinsic as SignedTransactionBuilder>::Extension>(), + ir.extra_ty + ); assert_eq!(meta_type::>(), ir.extra_ty); } diff --git a/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs new file mode 100644 index 000000000000..a2b916f54c5e --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_associated_types_metadata.rs @@ -0,0 +1,269 @@ +// 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 frame_support::{derive_impl, traits::ConstU32}; +use scale_info::meta_type; +use sp_metadata_ir::PalletAssociatedTypeMetadataIR; + +pub type BlockNumber = u64; +pub type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + +/// Pallet without collectable associated types. +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + // Runtime events already propagated to the metadata. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Constants are already propagated. + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::event] + pub enum Event { + TestEvent, + } +} + +/// Pallet with default collectable associated types. +#[frame_support::pallet] +pub mod pallet2 { + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + // Runtime events already propagated to the metadata. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Constants are already propagated. + #[pallet::constant] + type MyGetParam2: Get; + + // Associated type included by default, because it requires TypeInfo bound. + /// Nonce doc. + type Nonce: TypeInfo; + + // Associated type included by default, because it requires + // Parameter bound (indirect TypeInfo). + type AccountData: Parameter; + + // Associated type without metadata bounds, not included. + type NotIncluded: From; + } + + #[pallet::event] + pub enum Event { + TestEvent, + } +} + +/// Pallet with implicit collectable associated types. +#[frame_support::pallet] +pub mod pallet3 { + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + // Associated types are not collected by default. + #[pallet::config(without_automatic_metadata)] + pub trait Config: frame_system::Config { + // Runtime events already propagated to the metadata. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Constants are already propagated. + #[pallet::constant] + type MyGetParam2: Get; + + // Explicitly include associated types. + #[pallet::include_metadata] + type Nonce: TypeInfo; + + type AccountData: Parameter; + + type NotIncluded: From; + } + + #[pallet::event] + pub enum Event { + TestEvent, + } +} + +impl pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MyGetParam2 = ConstU32<10>; +} + +impl pallet2::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MyGetParam2 = ConstU32<10>; + type Nonce = u64; + type AccountData = u16; + type NotIncluded = u8; +} + +impl pallet3::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MyGetParam2 = ConstU32<10>; + type Nonce = u64; + type AccountData = u16; + type NotIncluded = u8; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type BaseCallFilter = frame_support::traits::Everything; + type RuntimeOrigin = RuntimeOrigin; + type Nonce = u64; + type RuntimeCall = RuntimeCall; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = sp_runtime::traits::IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +frame_support::construct_runtime!( + pub enum Runtime + { + System: frame_system, + Example: pallet, + DefaultInclusion: pallet2, + ExplicitInclusion: pallet3, + } +); + +#[test] +fn associated_types_metadata() { + fn maybe_docs(doc: Vec<&'static str>) -> Vec<&'static str> { + if cfg!(feature = "no-metadata-docs") { + vec![] + } else { + doc + } + } + + let ir = Runtime::metadata_ir(); + + // No associated types to collect. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "Example").unwrap(); + pretty_assertions::assert_eq!(pallet.associated_types, vec![]); + + // Collect by default types that implement TypeInfo or Parameter. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "DefaultInclusion").unwrap(); + pretty_assertions::assert_eq!( + pallet.associated_types, + vec![ + PalletAssociatedTypeMetadataIR { + name: "Nonce", + ty: meta_type::(), + docs: maybe_docs(vec![" Nonce doc."]), + }, + PalletAssociatedTypeMetadataIR { + name: "AccountData", + ty: meta_type::(), + docs: vec![], + } + ] + ); + + // Explicitly include associated types. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "ExplicitInclusion").unwrap(); + pretty_assertions::assert_eq!( + pallet.associated_types, + vec![PalletAssociatedTypeMetadataIR { + name: "Nonce", + ty: meta_type::(), + docs: vec![], + }] + ); + + // Check system pallet. + let pallet = ir.pallets.iter().find(|pallet| pallet.name == "System").unwrap(); + pretty_assertions::assert_eq!( + pallet.associated_types, + vec![ + PalletAssociatedTypeMetadataIR { + name: "RuntimeCall", + ty: meta_type::(), + docs: maybe_docs(vec![" The aggregated `RuntimeCall` type."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Nonce", + ty: meta_type::(), + docs: maybe_docs(vec![" This stores the number of previous transactions associated with a sender account."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Hash", + ty: meta_type::(), + docs: maybe_docs(vec![" The output of the `Hashing` function."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Hashing", + ty: meta_type::(), + docs: maybe_docs(vec![" The hashing system (algorithm) being used in the runtime (e.g. Blake2)."]), + }, + PalletAssociatedTypeMetadataIR { + name: "AccountId", + ty: meta_type::(), + docs: maybe_docs(vec![" The user account identifier type for the runtime."]), + }, + PalletAssociatedTypeMetadataIR { + name: "Block", + ty: meta_type::(), + docs: maybe_docs(vec![ + " The Block type used by the runtime. This is used by `construct_runtime` to retrieve the", + " extrinsics or other block specific data as needed.", + ]), + }, + PalletAssociatedTypeMetadataIR { + name: "AccountData", + ty: meta_type::<()>(), + docs: maybe_docs(vec![ + " Data to be associated with an account (other than nonce/transaction counter, which this", + " pallet does regardless).", + ]), + }, + ] + ); +} diff --git a/substrate/frame/support/test/tests/pallet_instance.rs b/substrate/frame/support/test/tests/pallet_instance.rs index 09a49617044d..2e4baae1db7c 100644 --- a/substrate/frame/support/test/tests/pallet_instance.rs +++ b/substrate/frame/support/test/tests/pallet_instance.rs @@ -360,7 +360,8 @@ fn call_expand() { assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { - weight: Weight::from_parts(3, 0), + call_weight: Weight::from_parts(3, 0), + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes } @@ -372,7 +373,8 @@ fn call_expand() { assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { - weight: Weight::from_parts(3, 0), + call_weight: Weight::from_parts(3, 0), + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes } @@ -940,9 +942,9 @@ fn metadata() { let extrinsic = ExtrinsicMetadata { ty: scale_info::meta_type::(), - version: 4, + version: 5, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitSignedExtension", + identifier: "UnitTransactionExtension", ty: scale_info::meta_type::<()>(), additional_signed: scale_info::meta_type::<()>(), }], diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs new file mode 100644 index 000000000000..f58e11b02261 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config(with_default, without_automatic_metadata, without_automatic_metadata)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr new file mode 100644 index 000000000000..46326bde0559 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_duplicate_attr.stderr @@ -0,0 +1,5 @@ +error: Invalid duplicated attribute for `#[pallet::config]`. Please remove duplicates: without_automatic_metadata. + --> tests/pallet_ui/config_duplicate_attr.rs:23:12 + | +23 | #[pallet::config(with_default, without_automatic_metadata, without_automatic_metadata)] + | ^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs new file mode 100644 index 000000000000..38c3870ba735 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.rs @@ -0,0 +1,42 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + + #[pallet::include_metadata] + type MyNonScaleTypeInfo; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr new file mode 100644 index 000000000000..362e97e8bb92 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_non_type_info.stderr @@ -0,0 +1,5 @@ +error: Invalid #[pallet::include_metadata] in #[pallet::config], collected type `MyNonScaleTypeInfo` does not implement `TypeInfo` or `Parameter` + --> tests/pallet_ui/config_metadata_non_type_info.rs:28:4 + | +28 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs new file mode 100644 index 000000000000..5452479b76e7 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.rs @@ -0,0 +1,40 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + #[pallet::constant] + #[pallet::include_metadata] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr new file mode 100644 index 000000000000..eb943158f38a --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_constants.stderr @@ -0,0 +1,5 @@ +error: Invalid #[pallet::include_metadata]: conflict with #[pallet::constant]. Pallet constant already collect the metadata for the type. + --> tests/pallet_ui/config_metadata_on_constants.rs:26:10 + | +26 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs new file mode 100644 index 000000000000..d91f86771bf6 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.rs @@ -0,0 +1,43 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config { + #[pallet::no_default_bounds] + #[pallet::include_metadata] + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr new file mode 100644 index 000000000000..15132ccce04c --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/config_metadata_on_events.stderr @@ -0,0 +1,5 @@ +error: Invalid #[pallet::include_metadata] for `type RuntimeEvent`. The associated type `RuntimeEvent` is already collected in the metadata. + --> tests/pallet_ui/config_metadata_on_events.rs:26:4 + | +26 | #[pallet::include_metadata] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr index e8df28a3046f..1b066bbe9fb8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/no_default_but_missing_with_default.stderr @@ -1,4 +1,4 @@ -error: `#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` has been specified +error: `#[pallet::no_default]` can only be used if `#[pallet::config(with_default)]` has been specified --> tests/pallet_ui/no_default_but_missing_with_default.rs:26:4 | 26 | #[pallet::no_default] diff --git a/substrate/frame/revive/src/benchmarking_dummy.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs similarity index 63% rename from substrate/frame/revive/src/benchmarking_dummy.rs rename to substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs index 6bb467911272..c016c52181cf 100644 --- a/substrate/frame/revive/src/benchmarking_dummy.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_multiple_attr.rs @@ -14,24 +14,19 @@ // 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. -// - -//! Defines a dummy benchmarking suite so that the build doesn't fail in case -//! no RISC-V toolchain is available. - -#![cfg(feature = "runtime-benchmarks")] -#![cfg(not(feature = "riscv"))] -use crate::{Config, *}; -use frame_benchmarking::v2::*; +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; -#[benchmarks] -mod benchmarks { - use super::*; - - #[benchmark(pov_mode = Ignored)] - fn enable_riscv_feature_to_unlock_benchmarks() { - #[block] - {} + #[pallet::config(with_default, without_automatic_metadata)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; } + + #[pallet::pallet] + pub struct Pallet(_); } + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs new file mode 100644 index 000000000000..c9f5244d7345 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/config_without_metadata.rs @@ -0,0 +1,32 @@ +// 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. + +#[frame_support::pallet] +mod pallet { + use frame_support::pallet_prelude::*; + + #[pallet::config(without_automatic_metadata)] + pub trait Config: frame_system::Config { + #[pallet::constant] + type MyGetParam2: Get; + } + + #[pallet::pallet] + pub struct Pallet(_); +} + +fn main() {} diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs b/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs index 234e220f49d8..bc66c09de7e8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs +++ b/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs @@ -39,5 +39,31 @@ mod pallet { } } +#[frame_support::pallet(dev_mode)] +mod pallet_with_instance { + use frame_support::pallet_prelude::{ValueQuery, StorageValue}; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type SomeStorage = StorageValue<_, u32, ValueQuery>; + + #[pallet::tasks_experimental] + impl, I> Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|i, j| i == 0u32 && j == 2u64)] + #[pallet::task_list(vec![(0u32, 2u64), (2u32, 4u64)].iter())] + #[pallet::task_weight(0.into())] + fn foo(_i: u32, _j: u64) -> frame_support::pallet_prelude::DispatchResult { + >::get(); + Ok(()) + } + } +} + fn main() { } diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen.rs b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen.rs new file mode 100644 index 000000000000..52ae19dcb02d --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet(dev_mode)] +mod pallet_with_instance { + use frame_support::pallet_prelude::{ValueQuery, StorageValue}; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type SomeStorage = StorageValue<_, u32, ValueQuery>; + + #[pallet::task_enum] + pub enum Task {} + + #[pallet::tasks_experimental] + impl frame_support::traits::Task for Task {} +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen.stderr new file mode 100644 index 000000000000..1dc9e3d4aa11 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen.stderr @@ -0,0 +1,5 @@ +error: Invalid generic declaration, trait is defined with instance but generic use none + --> tests/pallet_ui/task_invalid_gen.rs:32:11 + | +32 | pub enum Task {} + | ^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen2.rs b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen2.rs new file mode 100644 index 000000000000..56392cbad2dc --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen2.rs @@ -0,0 +1,39 @@ +// 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. + +#[frame_support::pallet(dev_mode)] +mod pallet_with_instance { + use frame_support::pallet_prelude::{ValueQuery, StorageValue}; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type SomeStorage = StorageValue<_, u32, ValueQuery>; + + #[pallet::task_enum] + pub enum Task {} + + #[pallet::tasks_experimental] + impl frame_support::traits::Task for Task {} +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen2.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen2.stderr new file mode 100644 index 000000000000..448825e60155 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_gen2.stderr @@ -0,0 +1,13 @@ +error: Invalid type def generics: expected `T` or `T: Config` or `T, I = ()` or `T: Config, I: 'static = ()` + --> tests/pallet_ui/task_invalid_gen2.rs:32:11 + | +32 | pub enum Task {} + | ^^^^ + +error: unexpected end of input, expected `T` + --> tests/pallet_ui/task_invalid_gen2.rs:18:1 + | +18 | #[frame_support::pallet(dev_mode)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/runtime.rs b/substrate/frame/support/test/tests/runtime.rs index 06c2b5b7071c..5335e08837e4 100644 --- a/substrate/frame/support/test/tests/runtime.rs +++ b/substrate/frame/support/test/tests/runtime.rs @@ -25,7 +25,10 @@ use codec::MaxEncodedLen; use frame_support::{ derive_impl, parameter_types, traits::PalletInfo as _, weights::RuntimeDbWeight, }; -use frame_system::limits::{BlockLength, BlockWeights}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + DispatchEventInfo, +}; use scale_info::TypeInfo; use sp_core::sr25519; use sp_runtime::{ @@ -533,8 +536,13 @@ fn origin_codec() { fn event_codec() { use codec::Encode; - let event = - frame_system::Event::::ExtrinsicSuccess { dispatch_info: Default::default() }; + let event = frame_system::Event::::ExtrinsicSuccess { + dispatch_info: DispatchEventInfo { + weight: Default::default(), + class: Default::default(), + pays_fee: Default::default(), + }, + }; assert_eq!(RuntimeEvent::from(event).encode()[0], 30); let event = module1::Event::::A(test_pub()); @@ -624,7 +632,8 @@ fn call_weight_should_attach_to_call_enum() { assert_eq!( module3::Call::::operational {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_parts(5, 0), + call_weight: Weight::from_parts(5, 0), + extension_weight: Default::default(), class: DispatchClass::Operational, pays_fee: Pays::Yes }, @@ -633,7 +642,8 @@ fn call_weight_should_attach_to_call_enum() { assert_eq!( module3::Call::::aux_4 {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_parts(3, 0), + call_weight: Weight::from_parts(3, 0), + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes }, @@ -894,7 +904,7 @@ fn test_metadata() { ty: meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitSignedExtension", + identifier: "UnitTransactionExtension", ty: meta_type::<()>(), additional_signed: meta_type::<()>(), }], diff --git a/substrate/frame/support/test/tests/runtime_legacy_ordering.rs b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs index 4233db21e203..7b92073a82b1 100644 --- a/substrate/frame/support/test/tests/runtime_legacy_ordering.rs +++ b/substrate/frame/support/test/tests/runtime_legacy_ordering.rs @@ -25,7 +25,10 @@ use codec::MaxEncodedLen; use frame_support::{ derive_impl, parameter_types, traits::PalletInfo as _, weights::RuntimeDbWeight, }; -use frame_system::limits::{BlockLength, BlockWeights}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + DispatchEventInfo, +}; use scale_info::TypeInfo; use sp_core::sr25519; use sp_runtime::{ @@ -533,8 +536,13 @@ fn origin_codec() { fn event_codec() { use codec::Encode; - let event = - frame_system::Event::::ExtrinsicSuccess { dispatch_info: Default::default() }; + let event = frame_system::Event::::ExtrinsicSuccess { + dispatch_info: DispatchEventInfo { + weight: Default::default(), + class: Default::default(), + pays_fee: Default::default(), + }, + }; assert_eq!(RuntimeEvent::from(event).encode()[0], 30); let event = module1::Event::::A(test_pub()); @@ -624,7 +632,8 @@ fn call_weight_should_attach_to_call_enum() { assert_eq!( module3::Call::::operational {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_parts(5, 0), + call_weight: Weight::from_parts(5, 0), + extension_weight: Default::default(), class: DispatchClass::Operational, pays_fee: Pays::Yes }, @@ -633,7 +642,8 @@ fn call_weight_should_attach_to_call_enum() { assert_eq!( module3::Call::::aux_4 {}.get_dispatch_info(), DispatchInfo { - weight: Weight::from_parts(3, 0), + call_weight: Weight::from_parts(3, 0), + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes }, @@ -894,7 +904,7 @@ fn test_metadata() { ty: meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { - identifier: "UnitSignedExtension", + identifier: "UnitTransactionExtension", ty: meta_type::<()>(), additional_signed: meta_type::<()>(), }], diff --git a/substrate/frame/support/test/tests/runtime_metadata.rs b/substrate/frame/support/test/tests/runtime_metadata.rs index 81377210eb43..7523a415d458 100644 --- a/substrate/frame/support/test/tests/runtime_metadata.rs +++ b/substrate/frame/support/test/tests/runtime_metadata.rs @@ -178,7 +178,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/support/test/tests/split_ui/pass/call/mod.rs b/substrate/frame/support/test/tests/split_ui/pass/call/mod.rs new file mode 100644 index 000000000000..27b3ec31b835 --- /dev/null +++ b/substrate/frame/support/test/tests/split_ui/pass/call/mod.rs @@ -0,0 +1,63 @@ +// 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 frame_support::pallet_macros::pallet_section; + +#[pallet_section] +mod call { + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + pub fn noop0(origin: OriginFor) -> DispatchResult { + ensure_signed(origin)?; + Ok(()) + } + + #[pallet::call_index(1)] + pub fn noop1(origin: OriginFor, _x: u64) -> DispatchResult { + ensure_signed(origin)?; + Ok(()) + } + + #[pallet::call_index(2)] + pub fn noop2(origin: OriginFor, _x: u64, _y: u64) -> DispatchResult { + ensure_signed(origin)?; + Ok(()) + } + + #[pallet::call_index(3)] + #[pallet::feeless_if(|_origin: &OriginFor| -> bool { true })] + pub fn noop_feeless0(origin: OriginFor) -> DispatchResult { + ensure_signed(origin)?; + Ok(()) + } + + #[pallet::call_index(4)] + #[pallet::feeless_if(|_origin: &OriginFor, x: &u64| -> bool { *x == 1 })] + pub fn noop_feeless1(origin: OriginFor, _x: u64) -> DispatchResult { + ensure_signed(origin)?; + Ok(()) + } + + #[pallet::call_index(5)] + #[pallet::feeless_if(|_origin: &OriginFor, x: &u64, y: &u64| -> bool { *x == *y })] + pub fn noop_feeless2(origin: OriginFor, _x: u64, _y: u64) -> DispatchResult { + ensure_signed(origin)?; + Ok(()) + } + } +} diff --git a/substrate/frame/support/test/tests/split_ui/pass/split_call.rs b/substrate/frame/support/test/tests/split_ui/pass/split_call.rs new file mode 100644 index 000000000000..09dbe6e3992d --- /dev/null +++ b/substrate/frame/support/test/tests/split_ui/pass/split_call.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. + +use frame_support::pallet_macros::import_section; + +mod call; + +#[import_section(call::call)] +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/split_ui/pass/split_storage.rs b/substrate/frame/support/test/tests/split_ui/pass/split_storage.rs new file mode 100644 index 000000000000..e8601587fac7 --- /dev/null +++ b/substrate/frame/support/test/tests/split_ui/pass/split_storage.rs @@ -0,0 +1,49 @@ +// 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 frame_support::pallet_macros::import_section; + +mod storage; + +#[import_section(storage::storage)] +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::call] + impl Pallet { + pub fn increment_value(_origin: OriginFor) -> DispatchResult { + Value::::mutate(|v| { + v.saturating_add(1) + }); + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/split_ui/pass/storage/mod.rs b/substrate/frame/support/test/tests/split_ui/pass/storage/mod.rs new file mode 100644 index 000000000000..26974a750dc3 --- /dev/null +++ b/substrate/frame/support/test/tests/split_ui/pass/storage/mod.rs @@ -0,0 +1,27 @@ +// 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 frame_support::pallet_macros::pallet_section; + +#[pallet_section] +mod storage { + #[pallet::storage] + pub type Value = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + pub type Map = StorageMap<_, _, u32, u32, ValueQuery>; +} diff --git a/substrate/frame/support/test/tests/tasks.rs b/substrate/frame/support/test/tests/tasks.rs new file mode 100644 index 000000000000..97e58388362b --- /dev/null +++ b/substrate/frame/support/test/tests/tasks.rs @@ -0,0 +1,135 @@ +// 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. + +#![cfg(feature = "experimental")] + +#[frame_support::pallet(dev_mode)] +mod my_pallet { + use frame_support::pallet_prelude::{StorageValue, ValueQuery}; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type SomeStorage = StorageValue<_, (u32, u64), ValueQuery>; + + #[pallet::tasks_experimental] + impl, I> Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|i, j| i == 0u32 && j == 2u64)] + #[pallet::task_list(vec![(0u32, 2u64), (2u32, 4u64)].iter())] + #[pallet::task_weight(0.into())] + fn foo(i: u32, j: u64) -> frame_support::pallet_prelude::DispatchResult { + >::put((i, j)); + Ok(()) + } + } +} + +// Another pallet for which we won't implement the default instance. +#[frame_support::pallet(dev_mode)] +mod my_pallet_2 { + use frame_support::pallet_prelude::{StorageValue, ValueQuery}; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type SomeStorage = StorageValue<_, (u32, u64), ValueQuery>; + + #[pallet::tasks_experimental] + impl, I> Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|i, j| i == 0u32 && j == 2u64)] + #[pallet::task_list(vec![(0u32, 2u64), (2u32, 4u64)].iter())] + #[pallet::task_weight(0.into())] + fn foo(i: u32, j: u64) -> frame_support::pallet_prelude::DispatchResult { + >::put((i, j)); + Ok(()) + } + } +} + +type BlockNumber = u32; +type AccountId = u64; +type Header = sp_runtime::generic::Header; +type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +type Block = sp_runtime::generic::Block; + +frame_support::construct_runtime!( + pub enum Runtime + { + System: frame_system, + MyPallet: my_pallet, + MyPallet2: my_pallet::, + #[cfg(feature = "frame-feature-testing")] + MyPallet3: my_pallet::, + MyPallet4: my_pallet_2::, + } +); + +// NOTE: Needed for derive_impl expansion +use frame_support::derive_impl; +#[frame_support::derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountId = AccountId; +} + +impl my_pallet::Config for Runtime {} + +impl my_pallet::Config for Runtime {} + +#[cfg(feature = "frame-feature-testing")] +impl my_pallet::Config for Runtime {} + +impl my_pallet_2::Config for Runtime {} + +fn new_test_ext() -> sp_io::TestExternalities { + use sp_runtime::BuildStorage; + + RuntimeGenesisConfig::default().build_storage().unwrap().into() +} + +#[test] +fn tasks_work() { + new_test_ext().execute_with(|| { + use frame_support::instances::{Instance1, Instance2}; + + let task = RuntimeTask::MyPallet(my_pallet::Task::::Foo { i: 0u32, j: 2u64 }); + + frame_support::assert_ok!(System::do_task(RuntimeOrigin::signed(1), task.clone(),)); + assert_eq!(my_pallet::SomeStorage::::get(), (0, 2)); + + let task = RuntimeTask::MyPallet2(my_pallet::Task::::Foo { i: 0u32, j: 2u64 }); + + frame_support::assert_ok!(System::do_task(RuntimeOrigin::signed(1), task.clone(),)); + assert_eq!(my_pallet::SomeStorage::::get(), (0, 2)); + + let task = + RuntimeTask::MyPallet4(my_pallet_2::Task::::Foo { i: 0u32, j: 2u64 }); + + frame_support::assert_ok!(System::do_task(RuntimeOrigin::signed(1), task.clone(),)); + assert_eq!(my_pallet_2::SomeStorage::::get(), (0, 2)); + }); +} diff --git a/substrate/frame/system/benchmarking/src/extensions.rs b/substrate/frame/system/benchmarking/src/extensions.rs new file mode 100644 index 000000000000..01e4687bc4bc --- /dev/null +++ b/substrate/frame/system/benchmarking/src/extensions.rs @@ -0,0 +1,258 @@ +// 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. + +// Benchmarks for System Extensions + +#![cfg(feature = "runtime-benchmarks")] + +use alloc::vec; +use frame_benchmarking::{account, v2::*, BenchmarkError}; +use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, + pallet_prelude::Zero, + weights::Weight, +}; +use frame_system::{ + pallet_prelude::*, CheckGenesis, CheckMortality, CheckNonZeroSender, CheckNonce, + CheckSpecVersion, CheckTxVersion, CheckWeight, Config, ExtensionsWeightInfo, Pallet as System, + RawOrigin, +}; +use sp_runtime::{ + generic::Era, + traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, Get, + }, +}; + +pub struct Pallet(System); + +#[benchmarks(where + T: Send + Sync, + T::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone) +] +mod benchmarks { + use super::*; + + #[benchmark] + fn check_genesis() -> Result<(), BenchmarkError> { + let len = 0_usize; + 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, 0, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + + Ok(()) + } + + #[benchmark] + fn check_mortality_mortal_transaction() -> Result<(), BenchmarkError> { + let len = 0_usize; + let ext = CheckMortality::::from(Era::mortal(16, 256)); + let block_number: BlockNumberFor = 17u32.into(); + System::::set_block_number(block_number); + let prev_block: BlockNumberFor = 16u32.into(); + let default_hash: T::Hash = Default::default(); + frame_system::BlockHash::::insert(prev_block, default_hash); + let caller = account("caller", 0, 0); + let info = DispatchInfo { + call_weight: Weight::from_parts(100, 0), + class: DispatchClass::Normal, + ..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, 0, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + Ok(()) + } + + #[benchmark] + fn check_mortality_immortal_transaction() -> Result<(), BenchmarkError> { + let len = 0_usize; + let ext = CheckMortality::::from(Era::immortal()); + let block_number: BlockNumberFor = 17u32.into(); + System::::set_block_number(block_number); + let prev_block: BlockNumberFor = 16u32.into(); + let default_hash: T::Hash = Default::default(); + frame_system::BlockHash::::insert(prev_block, default_hash); + let genesis_block: BlockNumberFor = 0u32.into(); + frame_system::BlockHash::::insert(genesis_block, default_hash); + let caller = account("caller", 0, 0); + let info = DispatchInfo { + call_weight: Weight::from_parts(100, 0), + class: DispatchClass::Normal, + ..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, 0, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + Ok(()) + } + + #[benchmark] + fn check_non_zero_sender() -> Result<(), BenchmarkError> { + let len = 0_usize; + let ext = CheckNonZeroSender::::new(); + 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(); + + #[block] + { + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + Ok(()) + } + + #[benchmark] + fn check_nonce() -> Result<(), BenchmarkError> { + let caller: T::AccountId = account("caller", 0, 0); + let mut info = frame_system::AccountInfo::default(); + info.nonce = 1u32.into(); + info.providers = 1; + let expected_nonce = info.nonce + 1u32.into(); + frame_system::Account::::insert(caller.clone(), info); + let len = 0_usize; + let ext = CheckNonce::::from(1u32.into()); + let info = DispatchInfo { call_weight: Weight::zero(), ..Default::default() }; + let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + + #[block] + { + ext.test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, len, 0, |_| { + Ok(().into()) + }) + .unwrap() + .unwrap(); + } + + let updated_info = frame_system::Account::::get(caller.clone()); + assert_eq!(updated_info.nonce, expected_nonce); + Ok(()) + } + + #[benchmark] + fn check_spec_version() -> Result<(), BenchmarkError> { + let len = 0_usize; + 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(); + + #[block] + { + CheckSpecVersion::::new() + .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + Ok(()) + } + + #[benchmark] + fn check_tx_version() -> Result<(), BenchmarkError> { + let len = 0_usize; + 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(); + + #[block] + { + CheckTxVersion::::new() + .test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(().into())) + .unwrap() + .unwrap(); + } + Ok(()) + } + + #[benchmark] + fn check_weight() -> Result<(), BenchmarkError> { + let caller = account("caller", 0, 0); + let base_extrinsic = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + let extension_weight = ::ExtensionsWeightInfo::check_weight(); + let info = DispatchInfo { + call_weight: Weight::from_parts(base_extrinsic.ref_time() * 5, 0), + extension_weight, + class: DispatchClass::Normal, + ..Default::default() + }; + let call: T::RuntimeCall = frame_system::Call::remark { remark: vec![] }.into(); + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(base_extrinsic.ref_time() * 2, 0)), + pays_fee: Default::default(), + }; + let len = 0_usize; + let base_extrinsic = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + + let ext = CheckWeight::::new(); + + let initial_block_weight = Weight::from_parts(base_extrinsic.ref_time() * 2, 0); + frame_system::BlockWeight::::mutate(|current_weight| { + current_weight.set(Weight::zero(), DispatchClass::Mandatory); + current_weight.set(initial_block_weight, DispatchClass::Normal); + }); + + #[block] + { + ext.test_run(RawOrigin::Signed(caller).into(), &call, &info, len, 0, |_| Ok(post_info)) + .unwrap() + .unwrap(); + } + + assert_eq!( + System::::block_weight().total(), + initial_block_weight + + base_extrinsic + + post_info.actual_weight.unwrap().saturating_add(extension_weight), + ); + Ok(()) + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test,); +} diff --git a/substrate/frame/system/benchmarking/src/lib.rs b/substrate/frame/system/benchmarking/src/lib.rs index f66d20ac8aed..dc3c7420317d 100644 --- a/substrate/frame/system/benchmarking/src/lib.rs +++ b/substrate/frame/system/benchmarking/src/lib.rs @@ -20,6 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; +pub mod extensions; #[cfg(feature = "runtime-benchmarks")] pub mod inner; diff --git a/substrate/frame/system/benchmarking/src/mock.rs b/substrate/frame/system/benchmarking/src/mock.rs index 42e4aa0eaf4b..6b126619ce5b 100644 --- a/substrate/frame/system/benchmarking/src/mock.rs +++ b/substrate/frame/system/benchmarking/src/mock.rs @@ -20,7 +20,7 @@ #![cfg(test)] use codec::Encode; -use frame_support::derive_impl; +use frame_support::{derive_impl, weights::Weight}; use sp_runtime::BuildStorage; type Block = frame_system::mocking::MockBlock; @@ -32,9 +32,45 @@ frame_support::construct_runtime!( } ); +pub struct MockWeights; +impl frame_system::ExtensionsWeightInfo for MockWeights { + fn check_genesis() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_mortality_mortal_transaction() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_mortality_immortal_transaction() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_non_zero_sender() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_nonce() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_spec_version() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_tx_version() -> Weight { + Weight::from_parts(10, 0) + } + + fn check_weight() -> Weight { + Weight::from_parts(10, 0) + } +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; + type ExtensionsWeightInfo = MockWeights; } impl crate::Config for Test {} diff --git a/substrate/frame/system/src/extensions/check_genesis.rs b/substrate/frame/system/src/extensions/check_genesis.rs index 000ec56da64f..881faa2c0eaf 100644 --- a/substrate/frame/system/src/extensions/check_genesis.rs +++ b/substrate/frame/system/src/extensions/check_genesis.rs @@ -19,7 +19,8 @@ use crate::{pallet_prelude::BlockNumberFor, Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension, Zero}, + impl_tx_ext_default, + traits::{TransactionExtension, Zero}, transaction_validity::TransactionValidityError, }; @@ -46,30 +47,24 @@ impl core::fmt::Debug for CheckGenesis { } impl CheckGenesis { - /// Creates new `SignedExtension` to check genesis hash. + /// Creates new `TransactionExtension` to check genesis hash. pub fn new() -> Self { Self(core::marker::PhantomData) } } -impl SignedExtension for CheckGenesis { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = T::Hash; - type Pre = (); +impl TransactionExtension for CheckGenesis { const IDENTIFIER: &'static str = "CheckGenesis"; - - fn additional_signed(&self) -> Result { + type Implicit = T::Hash; + fn implicit(&self) -> Result { Ok(>::block_hash(BlockNumberFor::::zero())) } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + type Val = (); + type Pre = (); + fn weight(&self, _: &T::RuntimeCall) -> sp_weights::Weight { + // All transactions will always read the hash of the genesis block, so to avoid + // charging this multiple times in a block we manually set the proof size to 0. + ::check_genesis().set_proof_size(0) } + impl_tx_ext_default!(T::RuntimeCall; validate prepare); } diff --git a/substrate/frame/system/src/extensions/check_mortality.rs b/substrate/frame/system/src/extensions/check_mortality.rs index 6666c4812fbc..e2c22a07a3fe 100644 --- a/substrate/frame/system/src/extensions/check_mortality.rs +++ b/substrate/frame/system/src/extensions/check_mortality.rs @@ -17,13 +17,13 @@ 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, - traits::{DispatchInfoOf, SaturatedConversion, SignedExtension}, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, - }, + impl_tx_ext_default, + traits::{DispatchInfoOf, SaturatedConversion, TransactionExtension, ValidateResult}, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; /// Check for transaction mortality. @@ -57,29 +57,11 @@ impl core::fmt::Debug for CheckMortality { } } -impl SignedExtension for CheckMortality { - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = T::Hash; - type Pre = (); +impl TransactionExtension for CheckMortality { const IDENTIFIER: &'static str = "CheckMortality"; + type Implicit = T::Hash; - fn validate( - &self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> TransactionValidity { - let current_u64 = >::block_number().saturated_into::(); - let valid_till = self.0.death(current_u64); - Ok(ValidTransaction { - longevity: valid_till.saturating_sub(current_u64), - ..Default::default() - }) - } - - fn additional_signed(&self) -> Result { + fn implicit(&self) -> Result { let current_u64 = >::block_number().saturated_into::(); let n = self.0.birth(current_u64).saturated_into::>(); if !>::contains_key(n) { @@ -88,16 +70,42 @@ impl SignedExtension for CheckMortality { Ok(>::block_hash(n)) } } + type Pre = (); + type Val = (); + + fn weight(&self, _: &T::RuntimeCall) -> sp_weights::Weight { + if self.0.is_immortal() { + // All immortal transactions will always read the hash of the genesis block, so to avoid + // charging this multiple times in a block we manually set the proof size to 0. + ::check_mortality_immortal_transaction() + .set_proof_size(0) + } else { + ::check_mortality_mortal_transaction() + } + } - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + fn validate( + &self, + origin: ::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _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); + Ok(( + ValidTransaction { + longevity: valid_till.saturating_sub(current_u64), + ..Default::default() + }, + (), + origin, + )) } + impl_tx_ext_default!(T::RuntimeCall; prepare); } #[cfg(test)] @@ -109,23 +117,23 @@ mod tests { weights::Weight, }; use sp_core::H256; + use sp_runtime::{ + traits::DispatchTransaction, transaction_validity::TransactionSource::External, + }; #[test] fn signed_ext_check_era_should_work() { new_test_ext().execute_with(|| { // future assert_eq!( - CheckMortality::::from(Era::mortal(4, 2)) - .additional_signed() - .err() - .unwrap(), + CheckMortality::::from(Era::mortal(4, 2)).implicit().err().unwrap(), InvalidTransaction::AncientBirthBlock.into(), ); // correct System::set_block_number(13); >::insert(12, H256::repeat_byte(1)); - assert!(CheckMortality::::from(Era::mortal(4, 12)).additional_signed().is_ok()); + assert!(CheckMortality::::from(Era::mortal(4, 12)).implicit().is_ok()); }) } @@ -133,7 +141,8 @@ mod tests { fn signed_ext_check_era_should_change_longevity() { new_test_ext().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; @@ -145,7 +154,13 @@ mod tests { System::set_block_number(17); >::insert(16, H256::repeat_byte(1)); - assert_eq!(ext.validate(&1, CALL, &normal, len).unwrap().longevity, 15); + assert_eq!( + 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 06dc2bf177ac..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,13 +18,12 @@ use crate::Config; use codec::{Decode, Encode}; use core::marker::PhantomData; -use frame_support::{dispatch::DispatchInfo, DefaultNoBound}; +use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, DefaultNoBound}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, SignedExtension}, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, - }, + impl_tx_ext_default, + traits::{DispatchInfoOf, TransactionExtension}, + transaction_validity::InvalidTransaction, }; /// Check to ensure that the sender is not the zero address. @@ -45,66 +44,83 @@ impl core::fmt::Debug for CheckNonZeroSender { } impl CheckNonZeroSender { - /// Create new `SignedExtension` to check runtime version. + /// Create new `TransactionExtension` to check runtime version. pub fn new() -> Self { Self(core::marker::PhantomData) } } -impl SignedExtension for CheckNonZeroSender -where - T::RuntimeCall: Dispatchable, -{ - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); +impl TransactionExtension for CheckNonZeroSender { const IDENTIFIER: &'static str = "CheckNonZeroSender"; + type Implicit = (); + type Val = (); + type Pre = (); - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + fn weight(&self, _: &T::RuntimeCall) -> sp_weights::Weight { + ::check_non_zero_sender() } fn validate( &self, - who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { - if who.using_encoded(|d| d.iter().all(|x| *x == 0)) { - return Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner)) + _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)) { + return Err(InvalidTransaction::BadSigner.into()) + } } - Ok(ValidTransaction::default()) + Ok((Default::default(), (), origin)) } + impl_tx_ext_default!(T::RuntimeCall; prepare); } #[cfg(test)] mod tests { use super::*; use crate::mock::{new_test_ext, Test, CALL}; - use frame_support::{assert_noop, assert_ok}; + use frame_support::{assert_ok, dispatch::DispatchInfo}; + use sp_runtime::{ + traits::{AsTransactionAuthorizedOrigin, DispatchTransaction}, + transaction_validity::{TransactionSource::External, TransactionValidityError}, + }; #[test] fn zero_account_ban_works() { new_test_ext().execute_with(|| { let info = DispatchInfo::default(); let len = 0_usize; - assert_noop!( - CheckNonZeroSender::::new().validate(&0, CALL, &info, len), - InvalidTransaction::BadSigner + assert_eq!( + CheckNonZeroSender::::new() + .validate_only(Some(0).into(), CALL, &info, len, External, 0) + .unwrap_err(), + TransactionValidityError::from(InvalidTransaction::BadSigner) ); - assert_ok!(CheckNonZeroSender::::new().validate(&1, CALL, &info, len)); + assert_ok!(CheckNonZeroSender::::new().validate_only( + Some(1).into(), + CALL, + &info, + len, + External, + 0, + )); + }) + } + + #[test] + fn unsigned_origin_works() { + new_test_ext().execute_with(|| { + let info = DispatchInfo::default(); + let len = 0_usize; + let (_, _, origin) = CheckNonZeroSender::::new() + .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 3535870d1b59..004ec08a26f2 100644 --- a/substrate/frame/system/src/extensions/check_nonce.rs +++ b/substrate/frame/system/src/extensions/check_nonce.rs @@ -18,23 +18,34 @@ use crate::Config; use alloc::vec; use codec::{Decode, Encode}; -use frame_support::dispatch::DispatchInfo; +use frame_support::{ + dispatch::DispatchInfo, pallet_prelude::TransactionSource, RuntimeDebugNoBound, +}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, One, SignedExtension, Zero}, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, + TransactionExtension, ValidateResult, Zero, + }, transaction_validity::{ - InvalidTransaction, TransactionLongevity, TransactionValidity, TransactionValidityError, - ValidTransaction, + InvalidTransaction, TransactionLongevity, TransactionValidityError, ValidTransaction, }, + DispatchResult, Saturating, }; +use sp_weights::Weight; /// Nonce check and increment to give replay protection for transactions. /// /// # Transaction Validity /// /// This extension affects `requires` and `provides` tags of validity, but DOES NOT -/// set the `priority` field. Make sure that AT LEAST one of the signed extension sets +/// set the `priority` field. Make sure that AT LEAST one of the transaction extension sets /// some kind of priority upon validating transactions. +/// +/// The preparation step assumes that the nonce information has not changed since the validation +/// step. This means that other extensions ahead of `CheckNonce` in the pipeline must not alter the +/// nonce during their own preparation step, or else the transaction may be rejected during dispatch +/// or lead to an inconsistent account state. #[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] #[scale_info(skip_type_params(T))] pub struct CheckNonce(#[codec(compact)] pub T::Nonce); @@ -58,83 +69,126 @@ impl core::fmt::Debug for CheckNonce { } } -impl SignedExtension for CheckNonce +/// Operation to perform from `validate` to `prepare` in [`CheckNonce`] transaction extension. +#[derive(RuntimeDebugNoBound)] +pub enum Val { + /// Account and its nonce to check for. + CheckNonce((T::AccountId, T::Nonce)), + /// Weight to refund. + Refund(Weight), +} + +/// Operation to perform from `prepare` to `post_dispatch_details` in [`CheckNonce`] transaction +/// extension. +#[derive(RuntimeDebugNoBound)] +pub enum Pre { + /// The transaction extension weight should not be refunded. + NonceChecked, + /// The transaction extension weight should be refunded. + Refund(Weight), +} + +impl TransactionExtension for CheckNonce where T::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, { - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); const IDENTIFIER: &'static str = "CheckNonce"; + type Implicit = (); + type Val = Val; + type Pre = Pre; - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result<(), TransactionValidityError> { - let mut account = crate::Account::::get(who); - if account.providers.is_zero() && account.sufficients.is_zero() { - // Nonce storage not paid for - return Err(InvalidTransaction::Payment.into()) - } - if self.0 != account.nonce { - return Err(if self.0 < account.nonce { - InvalidTransaction::Stale - } else { - InvalidTransaction::Future - } - .into()) - } - account.nonce += T::Nonce::one(); - crate::Account::::insert(who, account); - Ok(()) + fn weight(&self, _: &T::RuntimeCall) -> sp_weights::Weight { + ::check_nonce() } fn validate( &self, - who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { + _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)) + }; let account = crate::Account::::get(who); if account.providers.is_zero() && account.sufficients.is_zero() { // Nonce storage not paid for - return InvalidTransaction::Payment.into() + return Err(InvalidTransaction::Payment.into()) } if self.0 < account.nonce { - return InvalidTransaction::Stale.into() + return Err(InvalidTransaction::Stale.into()) } - let provides = vec![Encode::encode(&(who, self.0))]; + let provides = vec![Encode::encode(&(&who, self.0))]; let requires = if account.nonce < self.0 { - vec![Encode::encode(&(who, self.0 - One::one()))] + vec![Encode::encode(&(&who, self.0.saturating_sub(One::one())))] } else { vec![] }; - Ok(ValidTransaction { + let validity = ValidTransaction { priority: 0, requires, provides, longevity: TransactionLongevity::max_value(), propagate: true, - }) + }; + + Ok((validity, Val::CheckNonce((who.clone(), account.nonce)), origin)) + } + + fn prepare( + self, + val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + let (who, mut nonce) = match val { + Val::CheckNonce((who, nonce)) => (who, nonce), + Val::Refund(weight) => return Ok(Pre::Refund(weight)), + }; + + // `self.0 < nonce` already checked in `validate`. + if self.0 > nonce { + return Err(InvalidTransaction::Future.into()) + } + nonce += T::Nonce::one(); + crate::Account::::mutate(who, |account| account.nonce = nonce); + Ok(Pre::NonceChecked) + } + + fn post_dispatch_details( + pre: Self::Pre, + _info: &DispatchInfo, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + match pre { + Pre::NonceChecked => Ok(Weight::zero()), + Pre::Refund(weight) => Ok(weight), + } } } #[cfg(test)] mod tests { use super::*; - use crate::mock::{new_test_ext, Test, CALL}; - use frame_support::{assert_noop, assert_ok}; + use crate::mock::{new_test_ext, RuntimeCall, Test, CALL}; + use frame_support::{ + assert_ok, assert_storage_noop, dispatch::GetDispatchInfo, traits::OriginTrait, + }; + use sp_runtime::{ + traits::{AsTransactionAuthorizedOrigin, DispatchTransaction}, + transaction_validity::TransactionSource::External, + }; #[test] fn signed_ext_check_nonce_works() { @@ -152,22 +206,50 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // stale - assert_noop!( - CheckNonce::(0u64.into()).validate(&1, CALL, &info, len), - InvalidTransaction::Stale - ); - assert_noop!( - CheckNonce::(0u64.into()).pre_dispatch(&1, CALL, &info, len), - InvalidTransaction::Stale - ); + assert_storage_noop!({ + assert_eq!( + CheckNonce::(0u64.into()) + .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, 0) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Stale) + ); + }); // correct - assert_ok!(CheckNonce::(1u64.into()).validate(&1, CALL, &info, len)); - assert_ok!(CheckNonce::(1u64.into()).pre_dispatch(&1, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).validate_only( + Some(1).into(), + CALL, + &info, + len, + External, + 0, + )); + assert_ok!(CheckNonce::(1u64.into()).validate_and_prepare( + Some(1).into(), + CALL, + &info, + len, + 0, + )); // future - assert_ok!(CheckNonce::(5u64.into()).validate(&1, CALL, &info, len)); - assert_noop!( - CheckNonce::(5u64.into()).pre_dispatch(&1, CALL, &info, len), - InvalidTransaction::Future + assert_ok!(CheckNonce::(5u64.into()).validate_only( + Some(1).into(), + CALL, + &info, + len, + External, + 0, + )); + assert_eq!( + CheckNonce::(5u64.into()) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Future) ); }) } @@ -198,20 +280,139 @@ mod tests { let info = DispatchInfo::default(); let len = 0_usize; // Both providers and sufficients zero - assert_noop!( - CheckNonce::(1u64.into()).validate(&1, CALL, &info, len), - InvalidTransaction::Payment - ); - assert_noop!( - CheckNonce::(1u64.into()).pre_dispatch(&1, CALL, &info, len), - InvalidTransaction::Payment - ); + assert_storage_noop!({ + assert_eq!( + CheckNonce::(1u64.into()) + .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, 0) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::Payment) + ); + }); // Non-zero providers - assert_ok!(CheckNonce::(1u64.into()).validate(&2, CALL, &info, len)); - assert_ok!(CheckNonce::(1u64.into()).pre_dispatch(&2, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).validate_only( + Some(2).into(), + CALL, + &info, + len, + External, + 0, + )); + assert_ok!(CheckNonce::(1u64.into()).validate_and_prepare( + Some(2).into(), + CALL, + &info, + len, + 0, + )); // Non-zero sufficients - assert_ok!(CheckNonce::(1u64.into()).validate(&3, CALL, &info, len)); - assert_ok!(CheckNonce::(1u64.into()).pre_dispatch(&3, CALL, &info, len)); + assert_ok!(CheckNonce::(1u64.into()).validate_only( + Some(3).into(), + CALL, + &info, + len, + External, + 0, + )); + assert_ok!(CheckNonce::(1u64.into()).validate_and_prepare( + Some(3).into(), + CALL, + &info, + len, + 0, + )); + }) + } + + #[test] + fn unsigned_check_nonce_works() { + new_test_ext().execute_with(|| { + let info = DispatchInfo::default(); + let len = 0_usize; + let (_, val, origin) = CheckNonce::(1u64.into()) + .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)); + }) + } + + #[test] + fn check_nonce_preserves_account_data() { + new_test_ext().execute_with(|| { + crate::Account::::insert( + 1, + crate::AccountInfo { + nonce: 1u64.into(), + consumers: 0, + providers: 1, + sufficients: 0, + data: 0, + }, + ); + let info = DispatchInfo::default(); + let len = 0_usize; + // run the validation step + let (_, val, origin) = CheckNonce::(1u64.into()) + .validate(Some(1).into(), CALL, &info, len, (), CALL, External) + .unwrap(); + // mutate `AccountData` for the caller + crate::Account::::mutate(1, |info| { + info.data = 42; + }); + // run the preparation step + assert_ok!(CheckNonce::(1u64.into()).prepare(val, &origin, CALL, &info, len)); + // only the nonce should be altered by the preparation step + let expected_info = crate::AccountInfo { + nonce: 2u64.into(), + consumers: 0, + providers: 1, + sufficients: 0, + data: 42, + }; + assert_eq!(crate::Account::::get(1), expected_info); + }) + } + + #[test] + fn check_nonce_skipped_and_refund_for_other_origins() { + new_test_ext().execute_with(|| { + let ext = CheckNonce::(1u64.into()); + + let mut info = CALL.get_dispatch_info(); + info.extension_weight = ext.weight(CALL); + + // Ensure we test the refund. + assert!(info.extension_weight != Weight::zero()); + + let len = CALL.encoded_size(); + + let origin = crate::RawOrigin::Root.into(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); + + assert!(origin.as_system_ref().unwrap().is_root()); + + let pd_res = Ok(()); + let mut post_info = frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(info.total_weight()), + pays_fee: Default::default(), + }; + + as TransactionExtension>::post_dispatch( + pre, + &info, + &mut post_info, + len, + &pd_res, + ) + .unwrap(); + + assert_eq!(post_info.actual_weight, Some(info.call_weight)); }) } } diff --git a/substrate/frame/system/src/extensions/check_spec_version.rs b/substrate/frame/system/src/extensions/check_spec_version.rs index ee7e6f2efd00..ff86c6cd4695 100644 --- a/substrate/frame/system/src/extensions/check_spec_version.rs +++ b/substrate/frame/system/src/extensions/check_spec_version.rs @@ -19,7 +19,7 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, traits::TransactionExtension, transaction_validity::TransactionValidityError, }; @@ -46,30 +46,24 @@ impl core::fmt::Debug for CheckSpecVersion { } impl CheckSpecVersion { - /// Create new `SignedExtension` to check runtime version. + /// Create new `TransactionExtension` to check runtime version. pub fn new() -> Self { Self(core::marker::PhantomData) } } -impl SignedExtension for CheckSpecVersion { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = u32; - type Pre = (); +impl TransactionExtension<::RuntimeCall> + for CheckSpecVersion +{ const IDENTIFIER: &'static str = "CheckSpecVersion"; - - fn additional_signed(&self) -> Result { + type Implicit = u32; + fn implicit(&self) -> Result { Ok(>::runtime_version().spec_version) } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + type Val = (); + type Pre = (); + fn weight(&self, _: &::RuntimeCall) -> sp_weights::Weight { + ::check_spec_version() } + impl_tx_ext_default!(::RuntimeCall; validate prepare); } diff --git a/substrate/frame/system/src/extensions/check_tx_version.rs b/substrate/frame/system/src/extensions/check_tx_version.rs index 15983c2cd088..e3b7dfe7c928 100644 --- a/substrate/frame/system/src/extensions/check_tx_version.rs +++ b/substrate/frame/system/src/extensions/check_tx_version.rs @@ -19,7 +19,7 @@ use crate::{Config, Pallet}; use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, traits::TransactionExtension, transaction_validity::TransactionValidityError, }; @@ -46,29 +46,24 @@ impl core::fmt::Debug for CheckTxVersion { } impl CheckTxVersion { - /// Create new `SignedExtension` to check transaction version. + /// Create new `TransactionExtension` to check transaction version. pub fn new() -> Self { Self(core::marker::PhantomData) } } -impl SignedExtension for CheckTxVersion { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = u32; - type Pre = (); +impl TransactionExtension<::RuntimeCall> + for CheckTxVersion +{ const IDENTIFIER: &'static str = "CheckTxVersion"; - - fn additional_signed(&self) -> Result { + type Implicit = u32; + fn implicit(&self) -> Result { Ok(>::runtime_version().transaction_version) } - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + type Val = (); + type Pre = (); + fn weight(&self, _: &::RuntimeCall) -> sp_weights::Weight { + ::check_tx_version() } + impl_tx_ext_default!(::RuntimeCall; validate prepare); } diff --git a/substrate/frame/system/src/extensions/check_weight.rs b/substrate/frame/system/src/extensions/check_weight.rs index 22da2a5b9872..ee91478b90f3 100644 --- a/substrate/frame/system/src/extensions/check_weight.rs +++ b/substrate/frame/system/src/extensions/check_weight.rs @@ -19,12 +19,15 @@ 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; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, - transaction_validity::{InvalidTransaction, TransactionValidity, TransactionValidityError}, + traits::{ + DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension, ValidateResult, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, DispatchResult, }; use sp_weights::Weight; @@ -50,11 +53,11 @@ where ) -> Result<(), TransactionValidityError> { let max = T::BlockWeights::get().get(info.class).max_extrinsic; match max { - Some(max) if info.weight.any_gt(max) => { + Some(max) if info.total_weight().any_gt(max) => { log::debug!( target: LOG_TARGET, "Extrinsic {} is greater than the max extrinsic {}", - info.weight, + info.total_weight(), max, ); @@ -89,43 +92,73 @@ where } } - /// Creates new `SignedExtension` to check weight of the extrinsic. + /// Creates new `TransactionExtension` to check weight of the extrinsic. pub fn new() -> Self { Self(Default::default()) } + /// Do the validate checks. This can be applied to both signed and unsigned. + /// + /// It only checks that the block weight and length limit will not exceed. + /// + /// Returns the transaction validity and the next block length, to be used in `prepare`. + pub fn do_validate( + info: &DispatchInfoOf, + len: usize, + ) -> Result<(ValidTransaction, u32), TransactionValidityError> { + // If they return `Ok`, then it is below the limit. + let next_len = Self::check_block_length(info, len)?; + // during validation we skip block limit check. Since the `validate_transaction` + // call runs on an empty block anyway, by this we prevent `on_initialize` weight + // consumption from causing false negatives. + Self::check_extrinsic_weight(info)?; + + Ok((Default::default(), next_len)) + } + /// Do the pre-dispatch checks. This can be applied to both signed and unsigned. /// /// It checks and notes the new weight and length. - pub fn do_pre_dispatch( + pub fn do_prepare( info: &DispatchInfoOf, len: usize, + next_len: u32, ) -> Result<(), TransactionValidityError> { - let next_len = Self::check_block_length(info, len)?; - let all_weight = Pallet::::block_weight(); let maximum_weight = T::BlockWeights::get(); let next_weight = calculate_consumed_weight::(&maximum_weight, all_weight, info, len)?; - Self::check_extrinsic_weight(info)?; + // Extrinsic weight already checked in `validate`. crate::AllExtrinsicsLen::::put(next_len); crate::BlockWeight::::put(next_weight); Ok(()) } - /// Do the validate checks. This can be applied to both signed and unsigned. - /// - /// It only checks that the block weight and length limit will not exceed. - pub fn do_validate(info: &DispatchInfoOf, len: usize) -> TransactionValidity { - // ignore the next length. If they return `Ok`, then it is below the limit. - let _ = Self::check_block_length(info, len)?; - // during validation we skip block limit check. Since the `validate_transaction` - // call runs on an empty block anyway, by this we prevent `on_initialize` weight - // consumption from causing false negatives. - Self::check_extrinsic_weight(info)?; + pub fn do_post_dispatch( + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + ) -> Result<(), TransactionValidityError> { + let unspent = post_info.calc_unspent(info); + if unspent.any_gt(Weight::zero()) { + crate::BlockWeight::::mutate(|current_weight| { + current_weight.reduce(unspent, info.class); + }) + } + + log::trace!( + target: LOG_TARGET, + "Used block weight: {:?}", + crate::BlockWeight::::get(), + ); + + log::trace!( + target: LOG_TARGET, + "Used block length: {:?}", + Pallet::::all_extrinsics_len(), + ); - Ok(Default::default()) + Ok(()) } } @@ -143,7 +176,7 @@ where { // Also Consider extrinsic length as proof weight. let extrinsic_weight = info - .weight + .total_weight() .saturating_add(maximum_weight.get(info.class).base_extrinsic) .saturating_add(Weight::from_parts(0, len as u64)); let limit_per_class = maximum_weight.get(info.class); @@ -201,83 +234,79 @@ where Ok(all_weight) } -impl SignedExtension for CheckWeight +impl TransactionExtension for CheckWeight where T::RuntimeCall: Dispatchable, { - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); const IDENTIFIER: &'static str = "CheckWeight"; + type Implicit = (); + type Pre = (); + type Val = u32; /* next block length */ - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) + fn weight(&self, _: &T::RuntimeCall) -> Weight { + ::check_weight() } - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - info: &DispatchInfoOf, + fn validate( + &self, + origin: T::RuntimeOrigin, + _call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> Result<(), TransactionValidityError> { - Self::do_pre_dispatch(info, len) + _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)) } - fn validate( - &self, - _who: &Self::AccountId, - _call: &Self::Call, - info: &DispatchInfoOf, + fn prepare( + self, + val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { - Self::do_validate(info, len) + ) -> Result { + Self::do_prepare(info, len, val) } - fn pre_dispatch_unsigned( - _call: &Self::Call, - info: &DispatchInfoOf, + fn post_dispatch_details( + _pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Self::do_post_dispatch(info, post_info)?; + Ok(Weight::zero()) + } + + fn bare_validate( + _call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> Result<(), TransactionValidityError> { - Self::do_pre_dispatch(info, len) + ) -> frame_support::pallet_prelude::TransactionValidity { + Ok(Self::do_validate(info, len)?.0) } - fn validate_unsigned( - _call: &Self::Call, - info: &DispatchInfoOf, + fn bare_validate_and_prepare( + _call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { - Self::do_validate(info, len) + ) -> Result<(), TransactionValidityError> { + let (_, next_len) = Self::do_validate(info, len)?; + Self::do_prepare(info, len, next_len) } - fn post_dispatch( - _pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn bare_post_dispatch( + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, _len: usize, _result: &DispatchResult, ) -> Result<(), TransactionValidityError> { - let unspent = post_info.calc_unspent(info); - if unspent.any_gt(Weight::zero()) { - crate::BlockWeight::::mutate(|current_weight| { - current_weight.reduce(unspent, info.class); - }) - } - - log::trace!( - target: LOG_TARGET, - "Used block weight: {:?}", - crate::BlockWeight::::get(), - ); - - log::trace!( - target: LOG_TARGET, - "Used block length: {:?}", - Pallet::::all_extrinsics_len(), - ); - - Ok(()) + Self::do_post_dispatch(info, post_info) } } @@ -302,6 +331,7 @@ mod tests { }; use core::marker::PhantomData; use frame_support::{assert_err, assert_ok, dispatch::Pays, weights::Weight}; + use sp_runtime::traits::DispatchTransaction; fn block_weights() -> crate::limits::BlockWeights { ::BlockWeights::get() @@ -327,7 +357,7 @@ mod tests { fn check(call: impl FnOnce(&DispatchInfo, usize)) { new_test_ext().execute_with(|| { let max = DispatchInfo { - weight: Weight::MAX, + call_weight: Weight::MAX, class: DispatchClass::Mandatory, ..Default::default() }; @@ -338,7 +368,8 @@ mod tests { } check(|max, len| { - assert_ok!(CheckWeight::::do_pre_dispatch(max, len)); + let next_len = CheckWeight::::check_block_length(max, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(max, len, next_len)); assert_eq!(System::block_weight().total(), Weight::MAX); assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); @@ -351,7 +382,7 @@ mod tests { fn normal_extrinsic_limited_by_maximum_extrinsic_weight() { new_test_ext().execute_with(|| { let max = DispatchInfo { - weight: block_weights().get(DispatchClass::Normal).max_extrinsic.unwrap() + + call_weight: block_weights().get(DispatchClass::Normal).max_extrinsic.unwrap() + Weight::from_parts(1, 0), class: DispatchClass::Normal, ..Default::default() @@ -374,11 +405,14 @@ mod tests { .unwrap_or_else(|| weights.max_block); let base_weight = weights.get(DispatchClass::Operational).base_extrinsic; - let weight = operational_limit - base_weight; - let okay = - DispatchInfo { weight, class: DispatchClass::Operational, ..Default::default() }; + let call_weight = operational_limit - base_weight; + let okay = DispatchInfo { + call_weight, + class: DispatchClass::Operational, + ..Default::default() + }; let max = DispatchInfo { - weight: weight + Weight::from_parts(1, 0), + call_weight: call_weight + Weight::from_parts(1, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -410,18 +444,20 @@ mod tests { // So normal extrinsic can be 758 weight (-5 for base extrinsic weight) // And Operational can be 246 to produce a full block (-10 for base) let max_normal = - DispatchInfo { weight: Weight::from_parts(753, 0), ..Default::default() }; + DispatchInfo { call_weight: Weight::from_parts(753, 0), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_parts(246, 0), + call_weight: Weight::from_parts(246, 0), class: DispatchClass::Operational, ..Default::default() }; let len = 0_usize; - assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); + let next_len = CheckWeight::::check_block_length(&max_normal, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&max_normal, len, next_len)); assert_eq!(System::block_weight().total(), Weight::from_parts(768, 0)); - assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); + let next_len = CheckWeight::::check_block_length(&rest_operational, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&rest_operational, len, next_len)); assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); // Checking single extrinsic should not take current block weight into account. @@ -434,19 +470,21 @@ mod tests { new_test_ext().execute_with(|| { // We switch the order of `full_block_with_normal_and_operational` let max_normal = - DispatchInfo { weight: Weight::from_parts(753, 0), ..Default::default() }; + DispatchInfo { call_weight: Weight::from_parts(753, 0), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_parts(246, 0), + call_weight: Weight::from_parts(246, 0), class: DispatchClass::Operational, ..Default::default() }; let len = 0_usize; - assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); + let next_len = CheckWeight::::check_block_length(&rest_operational, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&rest_operational, len, next_len)); // Extra 20 here from block execution + base extrinsic weight assert_eq!(System::block_weight().total(), Weight::from_parts(266, 0)); - assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); + let next_len = CheckWeight::::check_block_length(&max_normal, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&max_normal, len, next_len)); assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); }); @@ -458,27 +496,30 @@ mod tests { // An on_initialize takes up the whole block! (Every time!) System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Mandatory); let dispatch_normal = DispatchInfo { - weight: Weight::from_parts(251, 0), + call_weight: Weight::from_parts(251, 0), class: DispatchClass::Normal, ..Default::default() }; let dispatch_operational = DispatchInfo { - weight: Weight::from_parts(246, 0), + call_weight: Weight::from_parts(246, 0), class: DispatchClass::Operational, ..Default::default() }; let len = 0_usize; + let next_len = CheckWeight::::check_block_length(&dispatch_normal, len).unwrap(); assert_err!( - CheckWeight::::do_pre_dispatch(&dispatch_normal, len), + CheckWeight::::do_prepare(&dispatch_normal, len, next_len), InvalidTransaction::ExhaustsResources ); + let next_len = + CheckWeight::::check_block_length(&dispatch_operational, len).unwrap(); // Thank goodness we can still do an operational transaction to possibly save the // blockchain. - assert_ok!(CheckWeight::::do_pre_dispatch(&dispatch_operational, len)); + assert_ok!(CheckWeight::::do_prepare(&dispatch_operational, len, next_len)); // Not too much though assert_err!( - CheckWeight::::do_pre_dispatch(&dispatch_operational, len), + CheckWeight::::do_prepare(&dispatch_operational, len, next_len), InvalidTransaction::ExhaustsResources ); // Even with full block, validity of single transaction should be correct. @@ -489,9 +530,11 @@ mod tests { #[test] fn signed_ext_check_weight_works_operational_tx() { new_test_ext().execute_with(|| { - let normal = DispatchInfo { weight: Weight::from_parts(100, 0), ..Default::default() }; + let normal = + DispatchInfo { call_weight: Weight::from_parts(100, 0), ..Default::default() }; let op = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -503,21 +546,37 @@ mod tests { current_weight.set(normal_limit, DispatchClass::Normal) }); // will not fit. - assert_err!( - CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &normal, len), - InvalidTransaction::ExhaustsResources + assert_eq!( + CheckWeight::(PhantomData) + .validate_and_prepare(Some(1).into(), CALL, &normal, len, 0) + .unwrap_err(), + InvalidTransaction::ExhaustsResources.into() ); // will fit. - assert_ok!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &op, len)); + assert_ok!(CheckWeight::(PhantomData).validate_and_prepare( + Some(1).into(), + CALL, + &op, + len, + 0, + )); // likewise for length limit. let len = 100_usize; AllExtrinsicsLen::::put(normal_length_limit()); - assert_err!( - CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &normal, len), - InvalidTransaction::ExhaustsResources + assert_eq!( + CheckWeight::(PhantomData) + .validate_and_prepare(Some(1).into(), CALL, &normal, len, 0) + .unwrap_err(), + InvalidTransaction::ExhaustsResources.into() ); - assert_ok!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &op, len)); + assert_ok!(CheckWeight::(PhantomData).validate_and_prepare( + Some(1).into(), + CALL, + &op, + len, + 0, + )); }) } @@ -528,7 +587,13 @@ mod tests { let normal_limit = normal_weight_limit().ref_time() as usize; let reset_check_weight = |tx, s, f| { AllExtrinsicsLen::::put(0); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, tx, s); + let r = CheckWeight::(PhantomData).validate_and_prepare( + Some(1).into(), + CALL, + tx, + s, + 0, + ); if f { assert!(r.is_err()) } else { @@ -542,7 +607,8 @@ mod tests { // Operational ones don't have this limit. let op = DispatchInfo { - weight: Weight::zero(), + call_weight: Weight::zero(), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -557,12 +623,13 @@ mod tests { fn signed_ext_check_weight_works_normal_tx() { new_test_ext().execute_with(|| { let normal_limit = normal_weight_limit(); - let small = DispatchInfo { weight: Weight::from_parts(100, 0), ..Default::default() }; + let small = + DispatchInfo { call_weight: Weight::from_parts(100, 0), ..Default::default() }; let base_extrinsic = block_weights().get(DispatchClass::Normal).base_extrinsic; let medium = - DispatchInfo { weight: normal_limit - base_extrinsic, ..Default::default() }; + DispatchInfo { call_weight: normal_limit - base_extrinsic, ..Default::default() }; let big = DispatchInfo { - weight: normal_limit - base_extrinsic + Weight::from_parts(1, 0), + call_weight: normal_limit - base_extrinsic + Weight::from_parts(1, 0), ..Default::default() }; let len = 0_usize; @@ -571,7 +638,13 @@ mod tests { BlockWeight::::mutate(|current_weight| { current_weight.set(s, DispatchClass::Normal) }); - let r = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, i, len); + let r = CheckWeight::(PhantomData).validate_and_prepare( + Some(1).into(), + CALL, + i, + len, + 0, + ); if f { assert!(r.is_err()) } else { @@ -589,7 +662,8 @@ mod tests { fn signed_ext_check_weight_refund_works() { new_test_ext().execute_with(|| { // This is half of the max block weight - let info = DispatchInfo { weight: Weight::from_parts(512, 0), ..Default::default() }; + let info = + DispatchInfo { call_weight: Weight::from_parts(512, 0), ..Default::default() }; let post_info = PostDispatchInfo { actual_weight: Some(Weight::from_parts(128, 0)), pays_fee: Default::default(), @@ -604,14 +678,17 @@ mod tests { .set(Weight::from_parts(256, 0) - base_extrinsic, DispatchClass::Normal); }); - let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); + let pre = CheckWeight::(PhantomData) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) + .unwrap() + .0; assert_eq!( BlockWeight::::get().total(), - info.weight + Weight::from_parts(256, 0) + info.total_weight() + Weight::from_parts(256, 0) ); - assert_ok!(CheckWeight::::post_dispatch( - Some(pre), + assert_ok!(CheckWeight::::post_dispatch_details( + pre, &info, &post_info, len, @@ -627,7 +704,8 @@ mod tests { #[test] fn signed_ext_check_weight_actual_weight_higher_than_max_is_capped() { new_test_ext().execute_with(|| { - let info = DispatchInfo { weight: Weight::from_parts(512, 0), ..Default::default() }; + let info = + DispatchInfo { call_weight: Weight::from_parts(512, 0), ..Default::default() }; let post_info = PostDispatchInfo { actual_weight: Some(Weight::from_parts(700, 0)), pays_fee: Default::default(), @@ -639,16 +717,19 @@ mod tests { current_weight.set(Weight::from_parts(128, 0), DispatchClass::Normal); }); - let pre = CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap(); + let pre = CheckWeight::(PhantomData) + .validate_and_prepare(Some(1).into(), CALL, &info, len, 0) + .unwrap() + .0; assert_eq!( BlockWeight::::get().total(), - info.weight + + info.total_weight() + Weight::from_parts(128, 0) + block_weights().get(DispatchClass::Normal).base_extrinsic, ); - assert_ok!(CheckWeight::::post_dispatch( - Some(pre), + assert_ok!(CheckWeight::::post_dispatch_details( + pre, &info, &post_info, len, @@ -656,7 +737,7 @@ mod tests { )); assert_eq!( BlockWeight::::get().total(), - info.weight + + info.total_weight() + Weight::from_parts(128, 0) + block_weights().get(DispatchClass::Normal).base_extrinsic, ); @@ -667,12 +748,18 @@ mod tests { fn zero_weight_extrinsic_still_has_base_weight() { new_test_ext().execute_with(|| { let weights = block_weights(); - let free = DispatchInfo { weight: Weight::zero(), ..Default::default() }; + let free = DispatchInfo { call_weight: Weight::zero(), ..Default::default() }; let len = 0_usize; // Initial weight from `weights.base_block` assert_eq!(System::block_weight().total(), weights.base_block); - assert_ok!(CheckWeight::(PhantomData).pre_dispatch(&1, CALL, &free, len)); + assert_ok!(CheckWeight::(PhantomData).validate_and_prepare( + Some(1).into(), + CALL, + &free, + len, + 0, + )); assert_eq!( System::block_weight().total(), weights.get(DispatchClass::Normal).base_extrinsic + weights.base_block @@ -687,18 +774,20 @@ mod tests { // Max normal is 768 (75%) // Max mandatory is unlimited let max_normal = - DispatchInfo { weight: Weight::from_parts(753, 0), ..Default::default() }; + DispatchInfo { call_weight: Weight::from_parts(753, 0), ..Default::default() }; let mandatory = DispatchInfo { - weight: Weight::from_parts(1019, 0), + call_weight: Weight::from_parts(1019, 0), class: DispatchClass::Mandatory, ..Default::default() }; let len = 0_usize; - assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); + let next_len = CheckWeight::::check_block_length(&max_normal, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&max_normal, len, next_len)); assert_eq!(System::block_weight().total(), Weight::from_parts(768, 0)); - assert_ok!(CheckWeight::::do_pre_dispatch(&mandatory, len)); + let next_len = CheckWeight::::check_block_length(&mandatory, len).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&mandatory, len, next_len)); assert_eq!(block_weight_limit(), Weight::from_parts(1024, u64::MAX)); assert_eq!(System::block_weight().total(), Weight::from_parts(1024 + 768, 0)); assert_eq!(CheckWeight::::check_extrinsic_weight(&mandatory), Ok(())); @@ -729,13 +818,13 @@ mod tests { // fits into reserved let mandatory1 = DispatchInfo { - weight: Weight::from_parts(5, 0), + call_weight: Weight::from_parts(5, 0), class: DispatchClass::Mandatory, ..Default::default() }; // does not fit into reserved and the block is full. let mandatory2 = DispatchInfo { - weight: Weight::from_parts(6, 0), + call_weight: Weight::from_parts(6, 0), class: DispatchClass::Mandatory, ..Default::default() }; @@ -778,13 +867,13 @@ mod tests { }); let normal = DispatchInfo { - weight: Weight::from_parts(5, 0), + call_weight: Weight::from_parts(5, 0), class: DispatchClass::Normal, ..Default::default() }; let mandatory = DispatchInfo { - weight: Weight::from_parts(5, 0), + call_weight: Weight::from_parts(5, 0), class: DispatchClass::Mandatory, ..Default::default() }; @@ -798,7 +887,7 @@ mod tests { ) .unwrap(); - assert_eq!(consumed.total().saturating_sub(all_weight.total()), normal.weight); + assert_eq!(consumed.total().saturating_sub(all_weight.total()), normal.total_weight()); let consumed = calculate_consumed_weight::<::RuntimeCall>( &maximum_weight, @@ -807,7 +896,7 @@ mod tests { 0, ) .unwrap(); - assert_eq!(consumed.total().saturating_sub(all_weight.total()), mandatory.weight); + assert_eq!(consumed.total().saturating_sub(all_weight.total()), mandatory.total_weight()); // Using non zero length extrinsics. let consumed = calculate_consumed_weight::<::RuntimeCall>( @@ -820,7 +909,7 @@ mod tests { // Must account for the len in the proof size assert_eq!( consumed.total().saturating_sub(all_weight.total()), - normal.weight.add_proof_size(100) + normal.total_weight().add_proof_size(100) ); let consumed = calculate_consumed_weight::<::RuntimeCall>( @@ -833,7 +922,7 @@ mod tests { // Must account for the len in the proof size assert_eq!( consumed.total().saturating_sub(all_weight.total()), - mandatory.weight.add_proof_size(100) + mandatory.total_weight().add_proof_size(100) ); // Using oversized zero length extrinsics. diff --git a/substrate/frame/system/src/extensions/mod.rs b/substrate/frame/system/src/extensions/mod.rs index a88c9fbf96eb..d79104d22403 100644 --- a/substrate/frame/system/src/extensions/mod.rs +++ b/substrate/frame/system/src/extensions/mod.rs @@ -22,3 +22,6 @@ pub mod check_nonce; pub mod check_spec_version; pub mod check_tx_version; pub mod check_weight; +pub mod weights; + +pub use weights::WeightInfo; diff --git a/substrate/frame/system/src/extensions/weights.rs b/substrate/frame/system/src/extensions/weights.rs new file mode 100644 index 000000000000..b3c296899be5 --- /dev/null +++ b/substrate/frame/system/src/extensions/weights.rs @@ -0,0 +1,209 @@ +// 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. + +//! Autogenerated weights for `frame_system_extensions` +//! +//! 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: `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 +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/system/src/extensions/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `frame_system_extensions`. +pub trait WeightInfo { + fn check_genesis() -> Weight; + fn check_mortality_mortal_transaction() -> Weight; + fn check_mortality_immortal_transaction() -> Weight; + fn check_non_zero_sender() -> Weight; + fn check_nonce() -> Weight; + fn check_spec_version() -> Weight; + fn check_tx_version() -> Weight; + fn check_weight() -> Weight; +} + +/// Weights for `frame_system_extensions` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `30` + // Estimated: `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: `68` + // Estimated: `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: `68` + // Estimated: `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: 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`) + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `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)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `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: 348_000 picoseconds. + Weight::from_parts(455_000, 0) + } + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_887_000 picoseconds. + Weight::from_parts(3_006_000, 0) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `30` + // Estimated: `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: `68` + // Estimated: `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: `68` + // Estimated: `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: 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`) + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `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)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `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: 348_000 picoseconds. + Weight::from_parts(455_000, 0) + } + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // 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 662b7f1a94bf..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, @@ -169,7 +170,7 @@ pub use extensions::{ check_genesis::CheckGenesis, check_mortality::CheckMortality, check_non_zero_sender::CheckNonZeroSender, check_nonce::CheckNonce, check_spec_version::CheckSpecVersion, check_tx_version::CheckTxVersion, - check_weight::CheckWeight, + check_weight::CheckWeight, WeightInfo as ExtensionsWeightInfo, }; // Backward compatible re-export. pub use extensions::check_mortality::CheckMortality as CheckEra; @@ -261,6 +262,19 @@ where check_version: bool, } +/// Information about the dispatch of a call, to be displayed in the +/// [`ExtrinsicSuccess`](Event::ExtrinsicSuccess) and [`ExtrinsicFailed`](Event::ExtrinsicFailed) +/// events. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct DispatchEventInfo { + /// Weight of this transaction. + pub weight: Weight, + /// Class of this transaction. + pub class: DispatchClass, + /// Does this transaction pay fees. + pub pays_fee: Pays, +} + #[frame_support::pallet] pub mod pallet { use crate::{self as frame_system, pallet_prelude::*, *}; @@ -297,12 +311,13 @@ 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 = (); type OnKilledAccount = (); type SystemWeightInfo = (); + type ExtensionsWeightInfo = (); type SS58Prefix = (); type Version = (); type BlockWeights = (); @@ -364,7 +379,7 @@ pub mod pallet { type MaxConsumers = frame_support::traits::ConstU32<128>; /// The default data to be stored in an account. - type AccountData = crate::AccountInfo; + type AccountData = (); /// What to do if a new account is created. type OnNewAccount = (); @@ -375,6 +390,9 @@ pub mod pallet { /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = (); + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = (); + /// This is used as an identifier of the chain. type SS58Prefix = (); @@ -490,6 +508,7 @@ pub mod pallet { type RuntimeCall: Parameter + Dispatchable + Debug + + GetDispatchInfo + From>; /// The aggregated `RuntimeTask` type. @@ -582,8 +601,12 @@ pub mod pallet { /// All resources should be cleaned up associated with the given account. type OnKilledAccount: OnKilledAccount; + /// Weight information for the extrinsics of this pallet. type SystemWeightInfo: WeightInfo; + /// Weight information for the transaction extensions of this pallet. + type ExtensionsWeightInfo: extensions::WeightInfo; + /// The designated SS58 prefix of this chain. /// /// This replaces the "ss58Format" property declared in the chain spec. Reason is @@ -833,9 +856,9 @@ pub mod pallet { #[pallet::event] pub enum Event { /// An extrinsic completed successfully. - ExtrinsicSuccess { dispatch_info: DispatchInfo }, + ExtrinsicSuccess { dispatch_info: DispatchEventInfo }, /// An extrinsic failed. - ExtrinsicFailed { dispatch_error: DispatchError, dispatch_info: DispatchInfo }, + ExtrinsicFailed { dispatch_error: DispatchError, dispatch_info: DispatchEventInfo }, /// `:code` was updated. CodeUpdated, /// A new account was created. @@ -921,6 +944,7 @@ pub mod pallet { /// Total length (in bytes) for all extrinsics put together, for the current block. #[pallet::storage] + #[pallet::whitelist_storage] pub type AllExtrinsicsLen = StorageValue<_, u32>; /// Map of block numbers to block hashes. @@ -949,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>; @@ -1137,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 } } } @@ -2025,13 +2050,15 @@ impl Pallet { /// Emits an `ExtrinsicSuccess` or `ExtrinsicFailed` event depending on the outcome. /// The emitted event contains the post-dispatch corrected weight including /// the base-weight for its dispatch class. - pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, mut info: DispatchInfo) { - info.weight = extract_actual_weight(r, &info) + pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, info: DispatchInfo) { + let weight = extract_actual_weight(r, &info) .saturating_add(T::BlockWeights::get().get(info.class).base_extrinsic); - info.pays_fee = extract_actual_pays_fee(r, &info); + let class = info.class; + let pays_fee = extract_actual_pays_fee(r, &info); + let dispatch_event_info = DispatchEventInfo { weight, class, pays_fee }; Self::deposit_event(match r { - Ok(_) => Event::ExtrinsicSuccess { dispatch_info: info }, + Ok(_) => Event::ExtrinsicSuccess { dispatch_info: dispatch_event_info }, Err(err) => { log::trace!( target: LOG_TARGET, @@ -2039,7 +2066,10 @@ impl Pallet { Self::block_number(), err, ); - Event::ExtrinsicFailed { dispatch_error: err.error, dispatch_info: info } + Event::ExtrinsicFailed { + dispatch_error: err.error, + dispatch_info: dispatch_event_info, + } }, }); 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/offchain.rs b/substrate/frame/system/src/offchain.rs index 1f72ea2d3745..bedfdded8183 100644 --- a/substrate/frame/system/src/offchain.rs +++ b/substrate/frame/system/src/offchain.rs @@ -58,9 +58,10 @@ use alloc::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec}; use codec::Encode; +use scale_info::TypeInfo; use sp_runtime::{ app_crypto::RuntimeAppPublic, - traits::{Extrinsic as ExtrinsicT, IdentifyAccount, One}, + traits::{ExtrinsicLike, IdentifyAccount, One}, RuntimeDebug, }; @@ -75,29 +76,18 @@ pub struct ForAny {} /// For submitting unsigned transactions, `submit_unsigned_transaction` /// utility function can be used. However, this struct is used by `Signer` /// to submit a signed transactions providing the signature along with the call. -pub struct SubmitTransaction, OverarchingCall> { - _phantom: core::marker::PhantomData<(T, OverarchingCall)>, +pub struct SubmitTransaction, RuntimeCall> { + _phantom: core::marker::PhantomData<(T, RuntimeCall)>, } impl SubmitTransaction where - T: SendTransactionTypes, + T: CreateTransactionBase, { - /// Submit transaction onchain by providing the call and an optional signature - pub fn submit_transaction( - call: >::OverarchingCall, - signature: Option<::SignaturePayload>, - ) -> Result<(), ()> { - let xt = T::Extrinsic::new(call, signature).ok_or(())?; + /// A convenience method to submit an extrinsic onchain. + pub fn submit_transaction(xt: T::Extrinsic) -> Result<(), ()> { sp_io::offchain::submit_transaction(xt.encode()) } - - /// A convenience method to submit an unsigned transaction onchain. - pub fn submit_unsigned_transaction( - call: >::OverarchingCall, - ) -> Result<(), ()> { - SubmitTransaction::::submit_transaction(call, None) - } } /// Provides an implementation for signing transaction payloads. @@ -284,7 +274,7 @@ impl< } impl< - T: SigningTypes + SendTransactionTypes, + T: SigningTypes + CreateInherent, C: AppCrypto, LocalCall, > SendUnsignedTransaction for Signer @@ -310,7 +300,7 @@ impl< } impl< - T: SigningTypes + SendTransactionTypes, + T: SigningTypes + CreateInherent, C: AppCrypto, LocalCall, > SendUnsignedTransaction for Signer @@ -457,25 +447,32 @@ pub trait SigningTypes: crate::Config { type Signature: Clone + PartialEq + core::fmt::Debug + codec::Codec + scale_info::TypeInfo; } -/// A definition of types required to submit transactions from within the runtime. -pub trait SendTransactionTypes { - /// The extrinsic type expected by the runtime. - type Extrinsic: ExtrinsicT + codec::Encode; +/// Common interface for the `CreateTransaction` trait family to unify the `Call` type. +pub trait CreateTransactionBase { + /// The extrinsic. + type Extrinsic: ExtrinsicLike + Encode; + /// The runtime's call type. /// /// This has additional bound to be able to be created from pallet-local `Call` types. - type OverarchingCall: From + codec::Encode; + type RuntimeCall: From + Encode; } -/// Create signed transaction. -/// -/// This trait is meant to be implemented by the runtime and is responsible for constructing -/// a payload to be signed and contained within the extrinsic. -/// This will most likely include creation of `SignedExtra` (a set of `SignedExtensions`). -/// Note that the result can be altered by inspecting the `Call` (for instance adjusting -/// fees, or mortality depending on the `pallet` being called). +/// Interface for creating a transaction. +pub trait CreateTransaction: CreateTransactionBase { + /// The extension. + type Extension: TypeInfo; + + /// Create a transaction using the call and the desired transaction extension. + fn create_transaction( + call: >::RuntimeCall, + extension: Self::Extension, + ) -> Self::Extrinsic; +} + +/// Interface for creating an old-school signed transaction. pub trait CreateSignedTransaction: - SendTransactionTypes + SigningTypes + CreateTransactionBase + SigningTypes { /// Attempt to create signed extrinsic data that encodes call from given account. /// @@ -483,12 +480,18 @@ pub trait CreateSignedTransaction: /// in any way it wants. /// Returns `None` if signed extrinsic could not be created (either because signing failed /// or because of any other runtime-specific reason). - fn create_transaction>( - call: Self::OverarchingCall, + fn create_signed_transaction>( + call: >::RuntimeCall, public: Self::Public, account: Self::AccountId, nonce: Self::Nonce, - ) -> Option<(Self::OverarchingCall, ::SignaturePayload)>; + ) -> Option; +} + +/// Interface for creating an inherent. +pub trait CreateInherent: CreateTransactionBase { + /// Create an inherent. + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic; } /// A message signer. @@ -516,7 +519,7 @@ pub trait SignMessage { /// Submit a signed transaction to the transaction pool. pub trait SendSignedTransaction< - T: SigningTypes + CreateSignedTransaction, + T: CreateSignedTransaction, C: AppCrypto, LocalCall, > @@ -547,13 +550,14 @@ pub trait SendSignedTransaction< account.id, account_data.nonce, ); - let (call, signature) = T::create_transaction::( + let transaction = T::create_signed_transaction::( call.into(), account.public.clone(), account.id.clone(), account_data.nonce, )?; - let res = SubmitTransaction::::submit_transaction(call, Some(signature)); + + let res = SubmitTransaction::::submit_transaction(transaction); if res.is_ok() { // increment the nonce. This is fine, since the code should always @@ -567,7 +571,7 @@ pub trait SendSignedTransaction< } /// Submit an unsigned transaction onchain with a signed payload -pub trait SendUnsignedTransaction, LocalCall> { +pub trait SendUnsignedTransaction, LocalCall> { /// A submission result. /// /// Should contain the submission result and the account(s) that signed the payload. @@ -590,7 +594,8 @@ pub trait SendUnsignedTransaction Option> { - Some(SubmitTransaction::::submit_unsigned_transaction(call.into())) + let xt = T::create_inherent(call.into()); + Some(SubmitTransaction::::submit_transaction(xt)) } } @@ -630,9 +635,15 @@ mod tests { type Extrinsic = TestXt; - impl SendTransactionTypes for TestRuntime { + impl CreateTransactionBase for TestRuntime { type Extrinsic = Extrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; + } + + impl CreateInherent for TestRuntime { + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } } #[derive(codec::Encode, codec::Decode)] @@ -693,7 +704,7 @@ mod tests { let _tx3 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert_eq!(tx1.signature, None); + assert!(tx1.is_inherent()); }); } @@ -724,7 +735,7 @@ mod tests { let tx1 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert_eq!(tx1.signature, None); + assert!(tx1.is_inherent()); }); } @@ -758,7 +769,7 @@ mod tests { let _tx2 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert_eq!(tx1.signature, None); + assert!(tx1.is_inherent()); }); } @@ -790,7 +801,7 @@ mod tests { let tx1 = pool_state.write().transactions.pop().unwrap(); assert!(pool_state.read().transactions.is_empty()); let tx1 = Extrinsic::decode(&mut &*tx1).unwrap(); - assert_eq!(tx1.signature, None); + assert!(tx1.is_inherent()); }); } } diff --git a/substrate/frame/system/src/tests.rs b/substrate/frame/system/src/tests.rs index aa1094e3fe48..6b903f5b7e79 100644 --- a/substrate/frame/system/src/tests.rs +++ b/substrate/frame/system/src/tests.rs @@ -266,7 +266,10 @@ fn deposit_event_should_work() { EventRecord { phase: Phase::ApplyExtrinsic(0), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } + dispatch_info: DispatchEventInfo { + weight: normal_base, + ..Default::default() + } } .into(), topics: vec![] @@ -275,7 +278,10 @@ fn deposit_event_should_work() { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } + dispatch_info: DispatchEventInfo { + weight: normal_base, + ..Default::default() + } } .into(), topics: vec![] @@ -300,7 +306,8 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { let normal_base = ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic; - let pre_info = DispatchInfo { weight: Weight::from_parts(1000, 0), ..Default::default() }; + let pre_info = + DispatchInfo { call_weight: Weight::from_parts(1000, 0), ..Default::default() }; System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(300))), pre_info); System::note_applied_extrinsic(&Ok(from_actual_ref_time(Some(1000))), pre_info); System::note_applied_extrinsic( @@ -356,7 +363,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { .base_extrinsic; assert!(normal_base != operational_base, "Test pre-condition violated"); let pre_info = DispatchInfo { - weight: Weight::from_parts(1000, 0), + call_weight: Weight::from_parts(1000, 0), class: DispatchClass::Operational, ..Default::default() }; @@ -367,7 +374,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(0), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(300, 0).saturating_add(normal_base), ..Default::default() }, @@ -378,7 +385,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), ..Default::default() }, @@ -389,7 +396,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(2), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), ..Default::default() }, @@ -400,10 +407,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(3), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::Yes, - ..Default::default() + class: Default::default(), }, } .into(), @@ -412,10 +419,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(4), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::No, - ..Default::default() + class: Default::default(), }, } .into(), @@ -424,10 +431,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(5), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::No, - ..Default::default() + class: Default::default(), }, } .into(), @@ -436,10 +443,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(6), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(500, 0).saturating_add(normal_base), pays_fee: Pays::No, - ..Default::default() + class: Default::default(), }, } .into(), @@ -449,7 +456,7 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(7), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(999, 0).saturating_add(normal_base), ..Default::default() }, @@ -461,10 +468,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(8), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(1000, 0).saturating_add(normal_base), pays_fee: Pays::Yes, - ..Default::default() + class: Default::default(), }, } .into(), @@ -474,10 +481,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(9), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(800, 0).saturating_add(normal_base), pays_fee: Pays::Yes, - ..Default::default() + class: Default::default(), }, } .into(), @@ -487,10 +494,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { phase: Phase::ApplyExtrinsic(10), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(800, 0).saturating_add(normal_base), pays_fee: Pays::No, - ..Default::default() + class: Default::default(), }, } .into(), @@ -499,10 +506,10 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { EventRecord { phase: Phase::ApplyExtrinsic(11), event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: Weight::from_parts(300, 0).saturating_add(operational_base), class: DispatchClass::Operational, - ..Default::default() + pays_fee: Default::default(), }, } .into(), 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/src/benchmarking.rs b/substrate/frame/timestamp/src/benchmarking.rs index d8c27b4967af..ef4d36c57691 100644 --- a/substrate/frame/timestamp/src/benchmarking.rs +++ b/substrate/frame/timestamp/src/benchmarking.rs @@ -19,43 +19,58 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; -use frame_benchmarking::v1::benchmarks; -use frame_support::{ensure, traits::OnFinalize}; +use frame_benchmarking::{benchmarking::add_to_whitelist, v2::*}; +use frame_support::traits::OnFinalize; use frame_system::RawOrigin; use sp_storage::TrackedStorageKey; -use crate::{Now, Pallet as Timestamp}; +use crate::*; const MAX_TIME: u32 = 100; -benchmarks! { - set { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn set() { let t = MAX_TIME; // Ignore write to `DidUpdate` since it transient. - let did_update_key = crate::DidUpdate::::hashed_key().to_vec(); - frame_benchmarking::benchmarking::add_to_whitelist(TrackedStorageKey { + let did_update_key = DidUpdate::::hashed_key().to_vec(); + add_to_whitelist(TrackedStorageKey { key: did_update_key, reads: 0, writes: 1, whitelisted: false, }); - }: _(RawOrigin::None, t.into()) - verify { - ensure!(Now::::get() == t.into(), "Time was not set."); + + #[extrinsic_call] + _(RawOrigin::None, t.into()); + + assert_eq!(Now::::get(), t.into(), "Time was not set."); } - on_finalize { + #[benchmark] + fn on_finalize() { let t = MAX_TIME; - Timestamp::::set(RawOrigin::None.into(), t.into())?; - ensure!(DidUpdate::::exists(), "Time was not set."); + Pallet::::set(RawOrigin::None.into(), t.into()).unwrap(); + assert!(DidUpdate::::exists(), "Time was not set."); + // Ignore read/write to `DidUpdate` since it is transient. - let did_update_key = crate::DidUpdate::::hashed_key().to_vec(); - frame_benchmarking::benchmarking::add_to_whitelist(did_update_key.into()); - }: { Timestamp::::on_finalize(t.into()); } - verify { - ensure!(!DidUpdate::::exists(), "Time was not removed."); + let did_update_key = DidUpdate::::hashed_key().to_vec(); + add_to_whitelist(did_update_key.into()); + + #[block] + { + Pallet::::on_finalize(t.into()); + } + + assert!(!DidUpdate::::exists(), "Time was not removed."); } - impl_benchmark_test_suite!(Timestamp, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite! { + Pallet, + mock::new_test_ext(), + mock::Test + } } 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/src/tests.rs b/substrate/frame/tips/src/tests.rs index 7e4a9368ad0c..530efb708e41 100644 --- a/substrate/frame/tips/src/tests.rs +++ b/substrate/frame/tips/src/tests.rs @@ -119,6 +119,7 @@ impl pallet_treasury::Config for Test { type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = ConstU64<10>; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -141,6 +142,7 @@ impl pallet_treasury::Config for Test { type Paymaster = PayFromAccount; type BalanceConverter = UnityAssetBalanceConversion; type PayoutPeriod = ConstU64<10>; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -207,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 4161a97f3cde..afa03ceb12eb 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -21,6 +21,7 @@ codec = { features = [ ], 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 } sp-core = { workspace = true } @@ -35,6 +36,7 @@ pallet-balances = { workspace = true, default-features = true } default = ["std"] std = [ "codec/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "pallet-balances/std", @@ -44,6 +46,13 @@ std = [ "sp-io/std", "sp-runtime/std", ] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", 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 e6a60e9c850f..7c98d157f6ff 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -18,6 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # Substrate dependencies sp-runtime = { workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } pallet-asset-conversion = { workspace = true } @@ -36,6 +37,7 @@ pallet-balances = { workspace = true, default-features = true } default = ["std"] std = [ "codec/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "pallet-asset-conversion/std", @@ -48,6 +50,16 @@ std = [ "sp-runtime/std", "sp-storage/std", ] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-asset-conversion/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md b/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md index eccba773673e..fcd1527526e9 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/README.md @@ -16,6 +16,6 @@ asset. ### Integration This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means you should include both pallets in your `construct_runtime` macro, but only include this -pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). +pallet's [`TransactionExtension`] ([`ChargeAssetTxPayment`]). License: Apache-2.0 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 new file mode 100644 index 000000000000..eb2635694e9c --- /dev/null +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/benchmarking.rs @@ -0,0 +1,127 @@ +// 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. + +//! Benchmarks for Asset Conversion Tx Payment Pallet's transaction extension + +extern crate alloc; + +use super::*; +use crate::Pallet; +use frame_benchmarking::v2::*; +use frame_support::{ + dispatch::{DispatchInfo, PostDispatchInfo}, + pallet_prelude::*, +}; +use frame_system::RawOrigin; +use sp_runtime::traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, +}; + +#[benchmarks(where + T::RuntimeOrigin: AsTransactionAuthorizedOrigin, + T::RuntimeCall: Dispatchable, + T::AssetId: Send + Sync, + BalanceOf: Send + + Sync + + From, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn charge_asset_tx_payment_zero() { + let caller: T::AccountId = account("caller", 0, 0); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(0u64.into(), None); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + call_weight: Weight::zero(), + extension_weight: Weight::zero(), + class: DispatchClass::Normal, + pays_fee: Pays::No, + }; + let post_info = PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }; + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_native() { + let caller: T::AccountId = account("caller", 0, 0); + let (fun_asset_id, _) = ::BenchmarkHelper::create_asset_id_parameter(1); + ::BenchmarkHelper::setup_balances_and_pool(fun_asset_id, caller.clone()); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(10u64.into(), None); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + call_weight: Weight::from_parts(10, 0), + extension_weight: Weight::zero(), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + // Submit a lower post info weight to trigger the refund path. + let post_info = + PostDispatchInfo { actual_weight: Some(Weight::from_parts(5, 0)), pays_fee: Pays::Yes }; + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_asset() { + let caller: T::AccountId = account("caller", 0, 0); + let (fun_asset_id, asset_id) = ::BenchmarkHelper::create_asset_id_parameter(1); + ::BenchmarkHelper::setup_balances_and_pool(fun_asset_id, caller.clone()); + + let tip = 10u64.into(); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(tip, Some(asset_id)); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + call_weight: Weight::from_parts(10, 0), + extension_weight: Weight::zero(), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + // Submit a lower post info weight to trigger the refund path. + let post_info = + PostDispatchInfo { actual_weight: Some(Weight::from_parts(5, 0)), pays_fee: Pays::Yes }; + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, 0, |_| Ok( + post_info + )) + .unwrap() + .is_ok()); + } + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); +} 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 825a35e62138..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 @@ -20,8 +20,8 @@ //! //! ## Overview //! -//! This pallet provides a `SignedExtension` with an optional `AssetId` that specifies the asset -//! to be used for payment (defaulting to the native token on `None`). It expects an +//! This pallet provides a `TransactionExtension` with an optional `AssetId` that specifies the +//! asset to be used for payment (defaulting to the native token on `None`). It expects an //! [`OnChargeAssetTransaction`] implementation analogous to [`pallet-transaction-payment`]. The //! included [`SwapAssetAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the //! fee amount by converting the fee calculated by [`pallet-transaction-payment`] in the native @@ -31,7 +31,7 @@ //! //! This pallet does not have any dispatchable calls or storage. It wraps FRAME's Transaction //! Payment pallet and functions as a replacement. This means you should include both pallets in -//! your `construct_runtime` macro, but only include this pallet's [`SignedExtension`] +//! your `construct_runtime` macro, but only include this pallet's [`TransactionExtension`] //! ([`ChargeAssetTxPayment`]). //! //! ## Terminology @@ -47,24 +47,33 @@ extern crate alloc; use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, + pallet_prelude::TransactionSource, traits::IsType, DefaultNoBound, }; -use pallet_transaction_payment::OnChargeTransaction; +use pallet_transaction_payment::{ChargeTransactionPayment, OnChargeTransaction}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction}, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, RefundWeight, + TransactionExtension, ValidateResult, Zero, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; #[cfg(test)] mod mock; #[cfg(test)] mod tests; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; mod payment; -use frame_support::traits::tokens::AssetId; +use frame_support::{pallet_prelude::Weight, traits::tokens::AssetId}; pub use payment::*; +pub use weights::WeightInfo; /// Balance type alias for balances of the chain's native asset. pub(crate) type BalanceOf = as OnChargeTransaction>::Balance; @@ -112,11 +121,30 @@ pub mod pallet { Balance = BalanceOf, AssetId = Self::AssetId, >; + /// The weight information of this pallet. + type WeightInfo: WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + /// Benchmark helper + type BenchmarkHelper: BenchmarkHelperTrait< + Self::AccountId, + Self::AssetId, + <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId, + >; } #[pallet::pallet] pub struct Pallet(_); + #[cfg(feature = "runtime-benchmarks")] + /// Helper trait to benchmark the `ChargeAssetTxPayment` transaction extension. + pub trait BenchmarkHelperTrait { + /// Returns the `AssetId` to be used in the liquidity pool by the benchmarking code. + fn create_asset_id_parameter(id: u32) -> (FunAssetIdParameter, AssetIdParameter); + /// Create a liquidity pool for a given asset and sufficiently endow accounts to benchmark + /// the extension. + fn setup_balances_and_pool(asset_id: FunAssetIdParameter, account: AccountId); + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -168,9 +196,8 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - len: usize, + fee: BalanceOf, ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { - let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); if fee.is_zero() { Ok((fee, InitialPayment::Nothing)) @@ -189,6 +216,28 @@ where .map(|payment| (fee, InitialPayment::Native(payment))) } } + + /// Fee withdrawal logic dry-run that dispatches to either `OnChargeAssetTransaction` or + /// `OnChargeTransaction`. + fn can_withdraw_fee( + &self, + who: &T::AccountId, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + fee: BalanceOf, + ) -> Result<(), TransactionValidityError> { + debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); + if fee.is_zero() { + Ok(()) + } else if let Some(asset_id) = &self.asset_id { + T::OnChargeAssetTransaction::can_withdraw_fee(who, asset_id.clone(), fee.into()) + } else { + as OnChargeTransaction>::can_withdraw_fee( + who, call, info, fee, self.tip, + ) + .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() }) + } + } } impl core::fmt::Debug for ChargeAssetTxPayment { @@ -202,108 +251,180 @@ impl core::fmt::Debug for ChargeAssetTxPayment { } } -impl SignedExtension for ChargeAssetTxPayment +/// The info passed between the validate and prepare steps for the `ChargeAssetTxPayment` extension. +pub enum Val { + Charge { + tip: BalanceOf, + // who paid the fee + who: T::AccountId, + // transaction fee + fee: BalanceOf, + }, + NoCharge, +} + +/// The info passed between the prepare and post-dispatch steps for the `ChargeAssetTxPayment` +/// extension. +pub enum Pre { + Charge { + tip: BalanceOf, + // who paid the fee + who: T::AccountId, + // imbalance resulting from withdrawing the fee + initial_payment: InitialPayment, + // weight used by the extension + weight: Weight, + }, + NoCharge { + // weight initially estimated by the extension, to be refunded + refund: Weight, + }, +} + +impl TransactionExtension for ChargeAssetTxPayment where T::RuntimeCall: Dispatchable, - BalanceOf: Send + Sync, + BalanceOf: Send + Sync + From, T::AssetId: Send + Sync, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = ( - // tip - BalanceOf, - // who paid the fee - Self::AccountId, - // imbalance resulting from withdrawing the fee - InitialPayment, - ); + type Implicit = (); + type Val = Val; + type Pre = Pre; - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) + fn weight(&self, _: &T::RuntimeCall) -> Weight { + if self.asset_id.is_some() { + ::WeightInfo::charge_asset_tx_payment_asset() + } else { + ::WeightInfo::charge_asset_tx_payment_native() + } } fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { - use pallet_transaction_payment::ChargeTransactionPayment; - let (fee, _) = self.withdraw_fee(who, call, info, len)?; + _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)) + }; + // Non-mutating call of `compute_fee` to calculate the fee used in the transaction priority. + let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); + self.can_withdraw_fee(&who, call, info, fee)?; let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - Ok(ValidTransaction { priority, ..Default::default() }) + let validity = ValidTransaction { priority, ..Default::default() }; + let val = Val::Charge { tip: self.tip, who: who.clone(), fee }; + Ok((validity, val, origin)) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, + val: Self::Val, + _origin: &::RuntimeOrigin, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + _len: usize, ) -> Result { - let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment)) + match val { + Val::Charge { tip, who, fee } => { + // Mutating call of `withdraw_fee` to actually charge for the transaction. + let (_fee, initial_payment) = self.withdraw_fee(&who, call, info, fee)?; + Ok(Pre::Charge { tip, who, initial_payment, weight: self.weight(call) }) + }, + Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }), + } } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, initial_payment)) = pre { - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - T::OnChargeTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee, - tip, - already_withdrawn, - )?; - pallet_transaction_payment::Pallet::::deposit_fee_paid_event( - who, actual_fee, tip, - ); - }, - InitialPayment::Asset((asset_id, already_withdrawn)) => { - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - let converted_fee = T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee, - tip, - asset_id.clone(), - already_withdrawn, - )?; - Pallet::::deposit_event(Event::::AssetTxFeePaid { - who, - actual_fee: converted_fee, - tip, - asset_id, - }); - }, - InitialPayment::Nothing => { - // `actual_fee` should be zero here for any signed extrinsic. It would be - // non-zero here in case of unsigned extrinsics as they don't pay fees but - // `compute_actual_fee` is not aware of them. In both cases it's fine to just - // move ahead without adjusting the fee, though, so we do nothing. - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, - } - } + ) -> Result { + let (tip, who, initial_payment, extension_weight) = match pre { + Pre::Charge { tip, who, initial_payment, weight } => + (tip, who, initial_payment, weight), + Pre::NoCharge { refund } => { + // No-op: Refund everything + return Ok(refund) + }, + }; - Ok(()) + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + // Take into account the weight used by this extension before calculating the + // refund. + let actual_ext_weight = ::WeightInfo::charge_asset_tx_payment_native(); + let unspent_weight = extension_weight.saturating_sub(actual_ext_weight); + let mut actual_post_info = *post_info; + actual_post_info.refund(unspent_weight); + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, + info, + &actual_post_info, + tip, + ); + T::OnChargeTransaction::correct_and_deposit_fee( + &who, + info, + &actual_post_info, + actual_fee, + tip, + already_withdrawn, + )?; + pallet_transaction_payment::Pallet::::deposit_fee_paid_event( + who, actual_fee, tip, + ); + Ok(unspent_weight) + }, + InitialPayment::Asset((asset_id, already_withdrawn)) => { + // Take into account the weight used by this extension before calculating the + // refund. + let actual_ext_weight = ::WeightInfo::charge_asset_tx_payment_asset(); + let unspent_weight = extension_weight.saturating_sub(actual_ext_weight); + let mut actual_post_info = *post_info; + actual_post_info.refund(unspent_weight); + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, + info, + &actual_post_info, + tip, + ); + let converted_fee = T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, + info, + &actual_post_info, + actual_fee, + tip, + asset_id.clone(), + already_withdrawn, + )?; + + Pallet::::deposit_event(Event::::AssetTxFeePaid { + who, + actual_fee: converted_fee, + tip, + asset_id, + }); + + Ok(unspent_weight) + }, + InitialPayment::Nothing => { + // `actual_fee` should be zero here for any signed extrinsic. It would be + // non-zero here in case of unsigned extrinsics as they don't pay fees but + // `compute_actual_fee` is not aware of them. In both cases it's fine to just + // move ahead without adjusting the fee, though, so we do nothing. + debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); + Ok(extension_weight + .saturating_sub(::WeightInfo::charge_asset_tx_payment_zero())) + }, + } } } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index acfd43d0a7cb..a86b86c223ef 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -145,6 +145,14 @@ impl OnUnbalanced::AccountId, } } +pub struct MockTxPaymentWeights; + +impl pallet_transaction_payment::WeightInfo for MockTxPaymentWeights { + fn charge_transaction_payment() -> Weight { + Weight::from_parts(10, 0) + } +} + pub struct DealWithFungiblesFees; impl OnUnbalanced> for DealWithFungiblesFees { fn on_unbalanceds( @@ -167,8 +175,8 @@ impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = FungibleAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = MockTxPaymentWeights; } type AssetId = u32; @@ -266,9 +274,95 @@ impl pallet_asset_conversion::Config for Runtime { } } +/// Weights used in testing. +pub struct MockWeights; + +impl WeightInfo for MockWeights { + fn charge_asset_tx_payment_zero() -> Weight { + Weight::from_parts(0, 0) + } + + fn charge_asset_tx_payment_native() -> Weight { + Weight::from_parts(15, 0) + } + + fn charge_asset_tx_payment_asset() -> Weight { + Weight::from_parts(20, 0) + } +} + impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type AssetId = NativeOrWithId; type OnChargeAssetTransaction = SwapAssetAdapter; + type WeightInfo = MockWeights; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = Helper; +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn new_test_ext() -> sp_io::TestExternalities { + let base_weight = 5; + let balance_factor = 100; + crate::tests::ExtBuilder::default() + .balance_factor(balance_factor) + .base_weight(Weight::from_parts(base_weight, 0)) + .build() +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct Helper; + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHelperTrait, NativeOrWithId> for Helper { + fn create_asset_id_parameter(id: u32) -> (NativeOrWithId, NativeOrWithId) { + (NativeOrWithId::WithId(id), NativeOrWithId::WithId(id)) + } + + fn setup_balances_and_pool(asset_id: NativeOrWithId, account: u64) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + use sp_runtime::traits::StaticLookup; + let NativeOrWithId::WithId(asset_idx) = asset_id.clone() else { unimplemented!() }; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_idx.into(), + 42, /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = 12; + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), lp_provider, u64::MAX / 2)); + let lp_provider_account = ::Lookup::unlookup(lp_provider); + assert_ok!(Assets::mint_into(asset_idx, &lp_provider_account, u64::MAX / 2)); + + let token_1 = Box::new(NativeOrWithId::Native); + let token_2 = Box::new(asset_id); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider), + token_1.clone(), + token_2.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider), + token_1, + token_2, + (u32::MAX / 8).into(), // 1 desired + u32::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider_account, + )); + + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&account, u32::MAX.into()); + + let beneficiary = ::Lookup::unlookup(account); + let balance = 1000; + + assert_ok!(Assets::mint_into(asset_idx, &beneficiary, balance)); + assert_eq!(Assets::balance(asset_idx, account), balance); + } } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs index dc7faecd5608..05182c3c9ee6 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs @@ -23,7 +23,7 @@ use frame_support::{ defensive, ensure, traits::{ fungibles, - tokens::{Balance, Fortitude, Precision, Preservation}, + tokens::{Balance, Fortitude, Precision, Preservation, WithdrawConsequence}, Defensive, OnUnbalanced, SameOrOther, }, unsigned::TransactionValidityError, @@ -56,6 +56,15 @@ pub trait OnChargeAssetTransaction { tip: Self::Balance, ) -> Result; + /// Ensure payment of the transaction fees can be withdrawn. + /// + /// Note: The `fee` already includes the tip. + fn can_withdraw_fee( + who: &T::AccountId, + asset_id: Self::AssetId, + fee: Self::Balance, + ) -> Result<(), TransactionValidityError>; + /// Refund any overpaid fees and deposit the corrected amount. /// The actual fee gets calculated once the transaction is executed. /// @@ -162,6 +171,51 @@ where Ok((fee_credit, asset_fee)) } + /// Dry run of swap & withdraw the predicted fee from the transaction origin. + /// + /// Note: The `fee` already includes the tip. + /// + /// Returns an error if the total amount in native currency can't be exchanged for `asset_id`. + fn can_withdraw_fee( + who: &T::AccountId, + asset_id: Self::AssetId, + fee: BalanceOf, + ) -> Result<(), TransactionValidityError> { + if asset_id == A::get() { + // The `asset_id` is the target asset, we do not need to swap. + match F::can_withdraw(asset_id.clone(), who, fee) { + WithdrawConsequence::BalanceLow | + WithdrawConsequence::UnknownAsset | + WithdrawConsequence::Underflow | + WithdrawConsequence::Overflow | + WithdrawConsequence::Frozen => + return Err(TransactionValidityError::from(InvalidTransaction::Payment)), + WithdrawConsequence::Success | + WithdrawConsequence::ReducedToZero(_) | + WithdrawConsequence::WouldDie => return Ok(()), + } + } + + let asset_fee = + S::quote_price_tokens_for_exact_tokens(asset_id.clone(), A::get(), fee, true) + .ok_or(InvalidTransaction::Payment)?; + + // Ensure we can withdraw enough `asset_id` for the swap. + match F::can_withdraw(asset_id.clone(), who, asset_fee) { + WithdrawConsequence::BalanceLow | + WithdrawConsequence::UnknownAsset | + WithdrawConsequence::Underflow | + WithdrawConsequence::Overflow | + WithdrawConsequence::Frozen => + return Err(TransactionValidityError::from(InvalidTransaction::Payment)), + WithdrawConsequence::Success | + WithdrawConsequence::ReducedToZero(_) | + WithdrawConsequence::WouldDie => {}, + }; + + Ok(()) + } + fn correct_and_deposit_fee( who: &T::AccountId, _dispatch_info: &DispatchInfoOf<::RuntimeCall>, 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 aab657199533..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 @@ -17,19 +17,23 @@ use super::*; use frame_support::{ assert_ok, - dispatch::{DispatchInfo, PostDispatchInfo}, + dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}, pallet_prelude::*, traits::{ fungible::{Inspect, NativeOrWithId}, fungibles::{Inspect as FungiblesInspect, Mutate}, tokens::{Fortitude, Precision, Preservation}, + OriginTrait, }, weights::Weight, }; use frame_system as system; use mock::{ExtrinsicBaseWeight, *}; use pallet_balances::Call as BalancesCall; -use sp_runtime::{traits::StaticLookup, BuildStorage}; +use sp_runtime::{ + traits::{DispatchTransaction, StaticLookup}, + BuildStorage, +}; const CALL: &::RuntimeCall = &RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); @@ -92,7 +96,7 @@ impl ExtBuilder { /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { // pays_fee: Pays::Yes -- class: DispatchClass::Normal - DispatchInfo { weight: w, ..Default::default() } + DispatchInfo { call_weight: w, ..Default::default() } } fn post_info_from_weight(w: Weight) -> PostDispatchInfo { @@ -161,35 +165,45 @@ fn transaction_payment_in_native_possible() { .build() .execute_with(|| { let len = 10; - let pre = ChargeAssetTxPayment::::from(0, None) - .pre_dispatch(&1, CALL, &info_from_weight(WEIGHT_5), len) - .unwrap(); + 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, 0).unwrap(); let initial_balance = 10 * balance_factor; - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); + assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 15 - 10); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(WEIGHT_5), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, &default_post_info(), len, - &Ok(()) + &Ok(()), )); - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); + assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 15 - 10); - let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(WEIGHT_100), len) - .unwrap(); + let mut info = info_from_weight(WEIGHT_100); + 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, 0).unwrap(); let initial_balance_for_2 = 20 * balance_factor; - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(WEIGHT_100), - &post_info_from_weight(WEIGHT_50), + assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 15 - 5); + let call_actual_weight = WEIGHT_50; + let post_info = post_info_from_weight( + info.call_weight + .saturating_sub(call_actual_weight) + .saturating_add(extension_weight), + ); + // The extension weight refund should be taken into account in `post_dispatch`. + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, + &post_info, len, - &Ok(()) + &Ok(()), )); - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); + assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 15 - 5); }); } @@ -240,8 +254,14 @@ fn transaction_payment_in_asset_possible() { let fee_in_asset = input_quote.unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .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); @@ -255,12 +275,12 @@ fn transaction_payment_in_asset_possible() { amount: fee_in_asset, })); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(WEIGHT_5), // estimated tx weight &default_post_info(), // weight actually used == estimated len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); @@ -298,12 +318,14 @@ fn transaction_payment_in_asset_fails_if_no_pool_for_that_asset() { assert_eq!(Assets::balance(asset_id, caller), balance); let len = 10; - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())).pre_dispatch( - &caller, - CALL, - &info_from_weight(WEIGHT_5), - len, - ); + let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .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()); @@ -353,8 +375,14 @@ fn transaction_payment_without_fee() { assert_eq!(input_quote, Some(201)); let fee_in_asset = input_quote.unwrap(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(WEIGHT_5), + len, + 0, + ) .unwrap(); // assert that native balance is not used @@ -371,12 +399,12 @@ fn transaction_payment_without_fee() { .unwrap(); assert_eq!(refund, 199); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(WEIGHT_5), &post_info_from_pays(Pays::No), len, - &Ok(()) + &Ok(()), )); // caller should get refunded @@ -419,24 +447,30 @@ fn asset_transaction_payment_with_tip_and_refund() { let weight = 100; let tip = 5; + let ext = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())); + let ext_weight = ext.weight(CALL); let len = 10; - let fee_in_native = base_weight + weight + len as u64 + tip; + let fee_in_native = base_weight + weight + ext_weight.ref_time() + len as u64 + tip; let input_quote = AssetConversion::quote_price_tokens_for_exact_tokens( NativeOrWithId::WithId(asset_id), NativeOrWithId::Native, fee_in_native, true, ); - assert_eq!(input_quote, Some(1206)); + assert_eq!(input_quote, Some(1407)); let fee_in_asset = input_quote.unwrap(); - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_100), len) - .unwrap(); + 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, 0).unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); let final_weight = 50; - let expected_fee = fee_in_native - final_weight - tip; + let weight_refund = weight - final_weight; + let ext_weight_refund = ext_weight - MockWeights::charge_asset_tx_payment_asset(); + let expected_fee = fee_in_native - weight_refund - ext_weight_refund.ref_time() - tip; let expected_token_refund = AssetConversion::quote_price_exact_tokens_for_tokens( NativeOrWithId::Native, NativeOrWithId::WithId(asset_id), @@ -451,12 +485,13 @@ fn asset_transaction_payment_with_tip_and_refund() { amount: fee_in_asset, })); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(WEIGHT_100), - &post_info_from_weight(WEIGHT_50), + let post_info = post_info_from_weight(WEIGHT_50.saturating_add(ext_weight)); + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, + &post_info, len, - &Ok(()) + &Ok(()), )); assert_eq!(TipUnbalancedAmount::get(), tip); @@ -522,18 +557,24 @@ fn payment_from_account_with_only_assets() { .unwrap(); assert_eq!(fee_in_asset, 201); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_5), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .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); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(WEIGHT_5), &default_post_info(), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); assert_eq!(Balances::free_balance(caller), 0); @@ -578,18 +619,24 @@ 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())) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .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); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_pays(Pays::No), &post_info_from_pays(Pays::No), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance); } @@ -604,17 +651,23 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { ) .unwrap(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); }); @@ -654,14 +707,16 @@ 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.into())) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id.into())) + .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); - let (_tip, _who, initial_payment) = ⪯ + let Pre::Charge { initial_payment, .. } = &pre else { + panic!("Expected Charge"); + }; let not_paying = match initial_payment { &InitialPayment::Nothing => true, _ => false, @@ -670,63 +725,12 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the // initial fee) - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_pays(Pays::No), &post_info_from_pays(Pays::Yes), len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance); - }); -} - -#[test] -fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { - let base_weight = 1; - ExtBuilder::default() - .balance_factor(100) - .base_weight(Weight::from_parts(base_weight, 0)) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 100; - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 1000; - - assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - - let weight = 1; - let len = 1; - ChargeAssetTxPayment::::pre_dispatch_unsigned( - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) - .unwrap(); - - assert_eq!(Assets::balance(asset_id, caller), balance); - - // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the - // initial fee) - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - None, - &info_from_weight(Weight::from_parts(weight, 0)), - &post_info_from_pays(Pays::Yes), - len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance); }); @@ -749,25 +753,35 @@ fn fee_with_native_asset_passed_with_id() { assert_eq!(Balances::free_balance(caller), caller_balance); let tip = 10; - let weight = 100; + let call_weight = 100; + let ext = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())); + let extension_weight = ext.weight(CALL); let len = 5; - let initial_fee = base_weight + weight + len as u64 + tip; + let initial_fee = + base_weight + call_weight + extension_weight.ref_time() + len as u64 + tip; - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_100), len) - .unwrap(); + 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, 0).unwrap(); assert_eq!(Balances::free_balance(caller), caller_balance - initial_fee); let final_weight = 50; + // No refunds from the extension weight itself. let expected_fee = initial_fee - final_weight; - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(WEIGHT_100), - &post_info_from_weight(WEIGHT_50), - len, - &Ok(()) - )); + let post_info = post_info_from_weight(WEIGHT_50.saturating_add(extension_weight)); + assert_eq!( + ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info_from_weight(WEIGHT_100), + &post_info, + len, + &Ok(()), + ) + .unwrap(), + Weight::zero() + ); assert_eq!(Balances::free_balance(caller), caller_balance - expected_fee); @@ -809,10 +823,13 @@ fn transfer_add_and_remove_account() { assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 100; + let call_weight = 100; let tip = 5; + let ext = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())); + let extension_weight = ext.weight(CALL); let len = 10; - let fee_in_native = base_weight + weight + len as u64 + tip; + let fee_in_native = + base_weight + call_weight + extension_weight.ref_time() + len as u64 + tip; let input_quote = AssetConversion::quote_price_tokens_for_exact_tokens( NativeOrWithId::WithId(asset_id), NativeOrWithId::Native, @@ -822,8 +839,10 @@ fn transfer_add_and_remove_account() { assert!(!input_quote.unwrap().is_zero()); let fee_in_asset = input_quote.unwrap(); - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id.into())) - .pre_dispatch(&caller, CALL, &info_from_weight(WEIGHT_100), len) + 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, 0) .unwrap(); assert_eq!(Assets::balance(asset_id, &caller), balance - fee_in_asset); @@ -838,7 +857,8 @@ fn transfer_add_and_remove_account() { Fortitude::Force )); - let final_weight = 50; + // Actual call weight + actual extension weight. + let final_weight = 50 + 20; let final_fee_in_native = fee_in_native - final_weight - tip; let token_refund = AssetConversion::quote_price_exact_tokens_for_tokens( NativeOrWithId::Native, @@ -851,12 +871,12 @@ fn transfer_add_and_remove_account() { // make sure the refund amount is enough to create the account. assert!(token_refund >= min_balance); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(WEIGHT_100), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, &post_info_from_weight(WEIGHT_50), len, - &Ok(()) + &Ok(()), )); // fee paid with no refund. @@ -867,3 +887,40 @@ fn transfer_add_and_remove_account() { assert_eq!(Assets::balance(asset_id, caller), 0); }); } + +#[test] +fn no_fee_and_no_weight_for_other_origins() { + ExtBuilder::default().build().execute_with(|| { + let ext = ChargeAssetTxPayment::::from(0, None); + + let mut info = CALL.get_dispatch_info(); + info.extension_weight = ext.weight(CALL); + + // Ensure we test the refund. + assert!(info.extension_weight != Weight::zero()); + + let len = CALL.encoded_size(); + + let origin = frame_system::RawOrigin::Root.into(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); + + assert!(origin.as_system_ref().unwrap().is_root()); + + let pd_res = Ok(()); + let mut post_info = frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(info.total_weight()), + pays_fee: Default::default(), + }; + + as TransactionExtension>::post_dispatch( + pre, + &info, + &mut post_info, + len, + &pd_res, + ) + .unwrap(); + + assert_eq!(post_info.actual_weight, Some(info.call_weight)); + }) +} 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 new file mode 100644 index 000000000000..587a399634b7 --- /dev/null +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs @@ -0,0 +1,132 @@ +// 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. + +//! Autogenerated weights for `pallet_asset_conversion_tx_payment` +//! +//! 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: `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 +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_asset_conversion_tx_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_asset_conversion_tx_payment`. +pub trait WeightInfo { + fn charge_asset_tx_payment_zero() -> Weight; + fn charge_asset_tx_payment_native() -> Weight; + fn charge_asset_tx_payment_asset() -> Weight; +} + +/// Weights for `pallet_asset_conversion_tx_payment` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 735_000 picoseconds. + Weight::from_parts(805_000, 0) + } + /// 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: `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: `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 charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `711` + // Estimated: `6208` + // 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)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 735_000 picoseconds. + Weight::from_parts(805_000, 0) + } + /// 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: `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: `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 charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `711` + // Estimated: `6208` + // 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 8d39dea8c62b..89fe5bfe7a42 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -64,6 +64,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ diff --git a/substrate/frame/transaction-payment/asset-tx-payment/README.md b/substrate/frame/transaction-payment/asset-tx-payment/README.md index fc860347d85f..933ce13b0ee6 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/README.md +++ b/substrate/frame/transaction-payment/asset-tx-payment/README.md @@ -16,6 +16,6 @@ asset. ### Integration This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means you should include both pallets in your `construct_runtime` macro, but only include this -pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). +pallet's [`TransactionExtension`] ([`ChargeAssetTxPayment`]). License: Apache-2.0 diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs new file mode 100644 index 000000000000..e4340cc6a152 --- /dev/null +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/benchmarking.rs @@ -0,0 +1,131 @@ +// 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. + +//! Benchmarks for Asset Tx Payment Pallet's transaction extension + +extern crate alloc; + +use super::*; +use crate::Pallet; +use frame_benchmarking::v2::*; +use frame_support::{ + dispatch::{DispatchInfo, PostDispatchInfo}, + pallet_prelude::*, +}; +use frame_system::RawOrigin; +use sp_runtime::traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable, +}; + +#[benchmarks(where + T::RuntimeOrigin: AsTransactionAuthorizedOrigin, + T::RuntimeCall: Dispatchable, + AssetBalanceOf: Send + Sync, + BalanceOf: Send + Sync + From + IsType>, + ChargeAssetIdOf: Send + Sync, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, + Credit: IsType>, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn charge_asset_tx_payment_zero() { + let caller: T::AccountId = account("caller", 0, 0); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(0u32.into(), None); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + call_weight: Weight::zero(), + extension_weight: Weight::zero(), + class: DispatchClass::Normal, + pays_fee: Pays::No, + }; + let post_info = PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }; + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_native() { + let caller: T::AccountId = account("caller", 0, 0); + let (fun_asset_id, _) = ::BenchmarkHelper::create_asset_id_parameter(1); + ::BenchmarkHelper::setup_balances_and_pool(fun_asset_id, caller.clone()); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(10u32.into(), None); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + call_weight: Weight::from_parts(10, 0), + extension_weight: Weight::zero(), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(10, 0)), + pays_fee: Pays::Yes, + }; + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller).into(), &call, &info, 0, 0, |_| Ok(post_info)) + .unwrap() + .is_ok()); + } + } + + #[benchmark] + fn charge_asset_tx_payment_asset() { + let caller: T::AccountId = account("caller", 0, 0); + let (fun_asset_id, asset_id) = ::BenchmarkHelper::create_asset_id_parameter(1); + ::BenchmarkHelper::setup_balances_and_pool( + fun_asset_id.clone(), + caller.clone(), + ); + let tip = 10u32.into(); + let ext: ChargeAssetTxPayment = ChargeAssetTxPayment::from(tip, Some(asset_id)); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let info = DispatchInfo { + call_weight: Weight::from_parts(10, 0), + extension_weight: Weight::zero(), + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(10, 0)), + pays_fee: Pays::Yes, + }; + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 0, 0, |_| Ok( + post_info + )) + .unwrap() + .is_ok()); + } + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); +} 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 97f1116993fc..dd752989c366 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -31,13 +31,14 @@ //! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means //! you should include both pallets in your `construct_runtime` macro, but only include this -//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). +//! pallet's [`TransactionExtension`] ([`ChargeAssetTxPayment`]). #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode}; use frame_support::{ dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, + pallet_prelude::{TransactionSource, Weight}, traits::{ tokens::{ fungibles::{Balanced, Credit, Inspect}, @@ -50,10 +51,11 @@ use frame_support::{ use pallet_transaction_payment::OnChargeTransaction; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, RefundWeight, + TransactionExtension, Zero, }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, }; #[cfg(test)] @@ -61,8 +63,14 @@ mod mock; #[cfg(test)] mod tests; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + mod payment; +pub mod weights; + pub use payment::*; +pub use weights::WeightInfo; /// Type aliases used for interaction with `OnChargeTransaction`. pub(crate) type OnChargeTransactionOf = @@ -118,11 +126,30 @@ pub mod pallet { type Fungibles: Balanced; /// The actual transaction charging logic that charges the fees. type OnChargeAssetTransaction: OnChargeAssetTransaction; + /// The weight information of this pallet. + type WeightInfo: WeightInfo; + /// Benchmark helper + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: BenchmarkHelperTrait< + Self::AccountId, + <::Fungibles as Inspect>::AssetId, + <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId, + >; } #[pallet::pallet] pub struct Pallet(_); + #[cfg(feature = "runtime-benchmarks")] + /// Helper trait to benchmark the `ChargeAssetTxPayment` transaction extension. + pub trait BenchmarkHelperTrait { + /// Returns the `AssetId` to be used in the liquidity pool by the benchmarking code. + fn create_asset_id_parameter(id: u32) -> (FunAssetIdParameter, AssetIdParameter); + /// Create a liquidity pool for a given asset and sufficiently endow accounts to benchmark + /// the extension. + fn setup_balances_and_pool(asset_id: FunAssetIdParameter, account: AccountId); + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -170,9 +197,8 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - len: usize, + fee: BalanceOf, ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { - let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); if fee.is_zero() { Ok((fee, InitialPayment::Nothing)) @@ -194,6 +220,35 @@ where .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() }) } } + + /// Fee withdrawal logic dry-run that dispatches to either `OnChargeAssetTransaction` or + /// `OnChargeTransaction`. + fn can_withdraw_fee( + &self, + who: &T::AccountId, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + fee: BalanceOf, + ) -> Result<(), TransactionValidityError> { + debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); + if fee.is_zero() { + Ok(()) + } else if let Some(asset_id) = self.asset_id { + T::OnChargeAssetTransaction::can_withdraw_fee( + who, + call, + info, + asset_id, + fee.into(), + self.tip.into(), + ) + } else { + as OnChargeTransaction>::can_withdraw_fee( + who, call, info, fee, self.tip, + ) + .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() }) + } + } } impl core::fmt::Debug for ChargeAssetTxPayment { @@ -207,106 +262,185 @@ impl core::fmt::Debug for ChargeAssetTxPayment { } } -impl SignedExtension for ChargeAssetTxPayment +/// The info passed between the validate and prepare steps for the `ChargeAssetTxPayment` extension. +pub enum Val { + Charge { + tip: BalanceOf, + // who paid the fee + who: T::AccountId, + // transaction fee + fee: BalanceOf, + }, + NoCharge, +} + +/// The info passed between the prepare and post-dispatch steps for the `ChargeAssetTxPayment` +/// extension. +pub enum Pre { + Charge { + tip: BalanceOf, + // who paid the fee + who: T::AccountId, + // imbalance resulting from withdrawing the fee + initial_payment: InitialPayment, + // asset_id for the transaction payment + asset_id: Option>, + // weight used by the extension + weight: Weight, + }, + NoCharge { + // weight initially estimated by the extension, to be refunded + refund: Weight, + }, +} + +impl TransactionExtension for ChargeAssetTxPayment where T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync, BalanceOf: Send + Sync + From + IsType>, ChargeAssetIdOf: Send + Sync, Credit: IsType>, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = ( - // tip - BalanceOf, - // who paid the fee - Self::AccountId, - // imbalance resulting from withdrawing the fee - InitialPayment, - // asset_id for the transaction payment - Option>, - ); + type Implicit = (); + type Val = Val; + type Pre = Pre; - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) + fn weight(&self, _: &T::RuntimeCall) -> Weight { + if self.asset_id.is_some() { + ::WeightInfo::charge_asset_tx_payment_asset() + } else { + ::WeightInfo::charge_asset_tx_payment_native() + } } fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { use pallet_transaction_payment::ChargeTransactionPayment; - let (fee, _) = self.withdraw_fee(who, call, info, len)?; + let Some(who) = origin.as_system_origin_signer() else { + return Ok((ValidTransaction::default(), Val::NoCharge, origin)) + }; + // Non-mutating call of `compute_fee` to calculate the fee used in the transaction priority. + let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); + self.can_withdraw_fee(&who, call, info, fee)?; let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - Ok(ValidTransaction { priority, ..Default::default() }) + let val = Val::Charge { tip: self.tip, who: who.clone(), fee }; + let validity = ValidTransaction { priority, ..Default::default() }; + Ok((validity, val, origin)) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, + val: Self::Val, + _origin: &::RuntimeOrigin, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + _len: usize, ) -> Result { - let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment, self.asset_id)) + match val { + Val::Charge { tip, who, fee } => { + // Mutating call of `withdraw_fee` to actually charge for the transaction. + let (_fee, initial_payment) = self.withdraw_fee(&who, call, info, fee)?; + Ok(Pre::Charge { + tip, + who, + initial_payment, + asset_id: self.asset_id, + weight: self.weight(call), + }) + }, + Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }), + } } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, initial_payment, asset_id)) = pre { - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch( - Some((tip, who, already_withdrawn)), + ) -> Result { + let (tip, who, initial_payment, asset_id, extension_weight) = match pre { + Pre::Charge { tip, who, initial_payment, asset_id, weight } => + (tip, who, initial_payment, asset_id, weight), + Pre::NoCharge { refund } => { + // No-op: Refund everything + return Ok(refund) + }, + }; + + match initial_payment { + InitialPayment::Native(already_withdrawn) => { + // Take into account the weight used by this extension before calculating the + // refund. + let actual_ext_weight = ::WeightInfo::charge_asset_tx_payment_native(); + let unspent_weight = extension_weight.saturating_sub(actual_ext_weight); + let mut actual_post_info = *post_info; + actual_post_info.refund(unspent_weight); + pallet_transaction_payment::ChargeTransactionPayment::::post_dispatch_details( + pallet_transaction_payment::Pre::Charge { + tip, + who, + imbalance: already_withdrawn, + }, + info, + &actual_post_info, + len, + result, + )?; + Ok(unspent_weight) + }, + InitialPayment::Asset(already_withdrawn) => { + let actual_ext_weight = ::WeightInfo::charge_asset_tx_payment_asset(); + let unspent_weight = extension_weight.saturating_sub(actual_ext_weight); + let mut actual_post_info = *post_info; + actual_post_info.refund(unspent_weight); + let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( + len as u32, + info, + &actual_post_info, + tip, + ); + + let (converted_fee, converted_tip) = + T::OnChargeAssetTransaction::correct_and_deposit_fee( + &who, info, - post_info, - len, - result, + &actual_post_info, + actual_fee.into(), + tip.into(), + already_withdrawn.into(), )?; - }, - InitialPayment::Asset(already_withdrawn) => { - let actual_fee = pallet_transaction_payment::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - - let (converted_fee, converted_tip) = - T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee.into(), - tip.into(), - already_withdrawn.into(), - )?; - Pallet::::deposit_event(Event::::AssetTxFeePaid { - who, - actual_fee: converted_fee, - tip: converted_tip, - asset_id, - }); - }, - InitialPayment::Nothing => { - // `actual_fee` should be zero here for any signed extrinsic. It would be - // non-zero here in case of unsigned extrinsics as they don't pay fees but - // `compute_actual_fee` is not aware of them. In both cases it's fine to just - // move ahead without adjusting the fee, though, so we do nothing. - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, - } + Pallet::::deposit_event(Event::::AssetTxFeePaid { + who, + actual_fee: converted_fee, + tip: converted_tip, + asset_id, + }); + Ok(unspent_weight) + }, + InitialPayment::Nothing => { + // `actual_fee` should be zero here for any signed extrinsic. It would be + // non-zero here in case of unsigned extrinsics as they don't pay fees but + // `compute_actual_fee` is not aware of them. In both cases it's fine to just + // move ahead without adjusting the fee, though, so we do nothing. + debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); + Ok(extension_weight + .saturating_sub(::WeightInfo::charge_asset_tx_payment_zero())) + }, } - - Ok(()) } } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs index e84df1e4eb91..fce029bb4bfc 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/mock.rs @@ -105,14 +105,22 @@ impl WeightToFeeT for TransactionByteFee { } } +pub struct MockTxPaymentWeights; + +impl pallet_transaction_payment::WeightInfo for MockTxPaymentWeights { + fn charge_transaction_payment() -> Weight { + Weight::from_parts(10, 0) + } +} + #[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = FungibleAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = MockTxPaymentWeights; } type AssetId = u32; @@ -168,6 +176,23 @@ impl HandleCredit for CreditToBlockAuthor { } } +/// Weights used in testing. +pub struct MockWeights; + +impl WeightInfo for MockWeights { + fn charge_asset_tx_payment_zero() -> Weight { + Weight::from_parts(0, 0) + } + + fn charge_asset_tx_payment_native() -> Weight { + Weight::from_parts(15, 0) + } + + fn charge_asset_tx_payment_asset() -> Weight { + Weight::from_parts(20, 0) + } +} + impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; @@ -175,4 +200,56 @@ impl Config for Runtime { pallet_assets::BalanceToAssetBalance, CreditToBlockAuthor, >; + type WeightInfo = MockWeights; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = Helper; +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn new_test_ext() -> sp_io::TestExternalities { + let base_weight = 5; + let balance_factor = 100; + crate::tests::ExtBuilder::default() + .balance_factor(balance_factor) + .base_weight(Weight::from_parts(base_weight, 0)) + .build() +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct Helper; + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHelperTrait for Helper { + fn create_asset_id_parameter(id: u32) -> (u32, u32) { + (id.into(), id.into()) + } + + fn setup_balances_and_pool(asset_id: u32, account: u64) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + use sp_runtime::traits::StaticLookup; + let min_balance = 1; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_id.into(), + 42, /* owner */ + true, /* is_sufficient */ + min_balance + )); + + // mint into the caller account + let caller = 2; + let beneficiary = ::Lookup::unlookup(caller); + let balance = 1000; + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, caller), balance); + + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&account, u32::MAX.into()); + + let beneficiary = ::Lookup::unlookup(account); + let balance = 1000; + + assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); + assert_eq!(Assets::balance(asset_id, account), balance); + } } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/payment.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/payment.rs index 2486474bad45..2074b1476f45 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -56,6 +56,18 @@ pub trait OnChargeAssetTransaction { tip: Self::Balance, ) -> Result; + /// Ensure payment of the transaction fees can be withdrawn. + /// + /// Note: The `fee` already includes the `tip`. + fn can_withdraw_fee( + who: &T::AccountId, + call: &T::RuntimeCall, + dispatch_info: &DispatchInfoOf, + asset_id: Self::AssetId, + fee: Self::Balance, + tip: Self::Balance, + ) -> Result<(), TransactionValidityError>; + /// After the transaction was executed the actual fee can be calculated. /// This function should refund any overpaid fees and optionally deposit /// the corrected amount. @@ -140,6 +152,32 @@ where .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) } + /// Ensure payment of the transaction fees can be withdrawn. + /// + /// Note: The `fee` already includes the `tip`. + fn can_withdraw_fee( + who: &T::AccountId, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + asset_id: Self::AssetId, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result<(), TransactionValidityError> { + // We don't know the precision of the underlying asset. Because the converted fee could be + // less than one (e.g. 0.5) but gets rounded down by integer division we introduce a minimum + // fee. + let min_converted_fee = if fee.is_zero() { Zero::zero() } else { One::one() }; + let converted_fee = CON::to_asset_balance(fee, asset_id) + .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))? + .max(min_converted_fee); + let can_withdraw = + >::can_withdraw(asset_id, who, converted_fee); + if can_withdraw != WithdrawConsequence::Success { + return Err(InvalidTransaction::Payment.into()) + } + Ok(()) + } + /// Hand the fee and the tip over to the `[HandleCredit]` implementation. /// Since the predicted fee might have been too high, parts of the fee may be refunded. /// 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 098ecf11dd92..6de2e8e7da55 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -17,15 +17,18 @@ use super::*; use frame_support::{ assert_ok, - dispatch::{DispatchInfo, PostDispatchInfo}, + dispatch::{DispatchInfo, GetDispatchInfo, PostDispatchInfo}, pallet_prelude::*, - traits::fungibles::Mutate, + traits::{fungibles::Mutate, OriginTrait}, weights::Weight, }; use frame_system as system; use mock::{ExtrinsicBaseWeight, *}; use pallet_balances::Call as BalancesCall; -use sp_runtime::{traits::StaticLookup, BuildStorage}; +use sp_runtime::{ + traits::{DispatchTransaction, StaticLookup}, + BuildStorage, +}; const CALL: &::RuntimeCall = &RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); @@ -88,7 +91,7 @@ impl ExtBuilder { /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { // pays_fee: Pays::Yes -- class: DispatchClass::Normal - DispatchInfo { weight: w, ..Default::default() } + DispatchInfo { call_weight: w, ..Default::default() } } fn post_info_from_weight(w: Weight) -> PostDispatchInfo { @@ -116,35 +119,49 @@ fn transaction_payment_in_native_possible() { .build() .execute_with(|| { let len = 10; - let pre = ChargeAssetTxPayment::::from(0, None) - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(5, 0)), len) - .unwrap(); + 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, 0).unwrap(); let initial_balance = 10 * balance_factor; - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); + assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 15 - 10); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(5, 0)), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, &default_post_info(), len, - &Ok(()) + &Ok(()), )); - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); + assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 15 - 10); - let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) - .unwrap(); + 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, 0).unwrap(); let initial_balance_for_2 = 20 * balance_factor; - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); + assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 15 - 5); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(100, 0)), - &post_info_from_weight(Weight::from_parts(50, 0)), + let call_actual_weight = Weight::from_parts(50, 0); + // The extension weight refund should be taken into account in `post_dispatch`. + let post_info = post_info_from_weight(call_actual_weight.saturating_add( + ChargeAssetTxPayment::::from(5 /* tipped */, None).weight(CALL), + )); + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, + &post_info, len, - &Ok(()) + &Ok(()), )); - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); + assert_eq!( + post_info.actual_weight, + Some( + call_actual_weight + .saturating_add(MockWeights::charge_asset_tx_payment_native()) + ) + ); + assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 15 - 5); }); } @@ -181,8 +198,14 @@ fn transaction_payment_in_asset_possible() { // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -196,12 +219,12 @@ fn transaction_payment_in_asset_possible() { amount: fee, })); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance - fee); // check that the block author gets rewarded @@ -246,8 +269,14 @@ fn transaction_payment_without_fee() { // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .unwrap(); // assert that native balance is not used assert_eq!(Balances::free_balance(caller), 10 * balance_factor); @@ -255,12 +284,12 @@ fn transaction_payment_without_fee() { assert_eq!(Assets::balance(asset_id, caller), balance - fee); assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(Weight::from_parts(weight, 0)), &post_info_from_pays(Pays::No), len, - &Ok(()) + &Ok(()), )); // caller should be refunded assert_eq!(Assets::balance(asset_id, caller), balance); @@ -298,14 +327,17 @@ fn asset_transaction_payment_with_tip_and_refund() { assert_eq!(Assets::balance(asset_id, caller), balance); let weight = 100; let tip = 5; + let ext = ChargeAssetTxPayment::::from(tip, Some(asset_id)); + let ext_weight = ext.weight(CALL); let len = 10; // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit - let fee_with_tip = - (base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) - .unwrap(); + let fee_with_tip = (base_weight + weight + ext_weight.ref_time() + len as u64 + tip) * + 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, 0).unwrap(); assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); System::assert_has_event(RuntimeEvent::Assets(pallet_assets::Event::Withdrawn { @@ -315,15 +347,22 @@ fn asset_transaction_payment_with_tip_and_refund() { })); let final_weight = 50; - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(weight, 0)), - &post_info_from_weight(Weight::from_parts(final_weight, 0)), + let mut post_info = post_info_from_weight(Weight::from_parts(final_weight, 0)); + post_info + .actual_weight + .as_mut() + .map(|w| w.saturating_accrue(MockWeights::charge_asset_tx_payment_asset())); + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, + &info, + &post_info, len, - &Ok(()) + &Ok(()), )); - let final_fee = - fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); + let final_fee = fee_with_tip - + (weight - final_weight + ext_weight.ref_time() - + MockWeights::charge_asset_tx_payment_asset().ref_time()) * + min_balance / ExistentialDeposit::get(); assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee)); assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee); @@ -367,19 +406,25 @@ fn payment_from_account_with_only_assets() { // we convert the from weight to fee based on the ratio between asset min balance and // existential deposit let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .unwrap(); assert_eq!(Balances::free_balance(caller), 0); // check that fee was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance - fee); assert_eq!(Balances::free_balance(caller), 0); @@ -400,7 +445,13 @@ fn payment_only_with_existing_sufficient_asset() { let len = 10; // pre_dispatch fails for non-existent asset assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .is_err()); // create the non-sufficient asset @@ -414,7 +465,13 @@ fn payment_only_with_existing_sufficient_asset() { )); // pre_dispatch fails for non-sufficient asset assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .is_err()); }); } @@ -452,33 +509,45 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { // naive fee calculation would round down to zero assert_eq!(fee, 0); { - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .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); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_pays(Pays::No), &post_info_from_pays(Pays::No), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance); } - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(Weight::from_parts(weight, 0)), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .validate_and_prepare( + Some(caller).into(), + CALL, + &info_from_weight(Weight::from_parts(weight, 0)), + len, + 0, + ) .unwrap(); // check that at least one coin was charged in the given asset assert_eq!(Assets::balance(asset_id, caller), balance - 1); - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_weight(Weight::from_parts(weight, 0)), &default_post_info(), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance - 1); }); @@ -516,12 +585,14 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); // calculated fee is greater than 0 assert!(fee > 0); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) + let (pre, _) = ChargeAssetTxPayment::::from(0, Some(asset_id)) + .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); - let (_tip, _who, initial_payment, _asset_id) = ⪯ + let Pre::Charge { initial_payment, .. } = &pre else { + panic!("Expected Charge"); + }; let not_paying = match initial_payment { &InitialPayment::Nothing => true, _ => false, @@ -530,62 +601,50 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the // initial fee) - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), + assert_ok!(ChargeAssetTxPayment::::post_dispatch_details( + pre, &info_from_pays(Pays::No), &post_info_from_pays(Pays::Yes), len, - &Ok(()) + &Ok(()), )); assert_eq!(Assets::balance(asset_id, caller), balance); }); } #[test] -fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { - let base_weight = 1; - ExtBuilder::default() - .balance_factor(100) - .base_weight(Weight::from_parts(base_weight, 0)) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 100; - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - asset_id.into(), - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); +fn no_fee_and_no_weight_for_other_origins() { + ExtBuilder::default().build().execute_with(|| { + let ext = ChargeAssetTxPayment::::from(0, None); - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id.into(), &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 1; - let len = 1; - ChargeAssetTxPayment::::pre_dispatch_unsigned( - CALL, - &info_from_weight(Weight::from_parts(weight, 0)), - len, - ) - .unwrap(); + let mut info = CALL.get_dispatch_info(); + info.extension_weight = ext.weight(CALL); - assert_eq!(Assets::balance(asset_id, caller), balance); + // Ensure we test the refund. + assert!(info.extension_weight != Weight::zero()); - // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the - // initial fee) - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - None, - &info_from_weight(Weight::from_parts(weight, 0)), - &post_info_from_pays(Pays::Yes), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance); - }); + let len = CALL.encoded_size(); + + let origin = frame_system::RawOrigin::Root.into(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); + + assert!(origin.as_system_ref().unwrap().is_root()); + + let pd_res = Ok(()); + let mut post_info = frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(info.total_weight()), + pays_fee: Default::default(), + }; + + as TransactionExtension>::post_dispatch( + pre, + &info, + &mut post_info, + len, + &pd_res, + ) + .unwrap(); + + assert_eq!(post_info.actual_weight, Some(info.call_weight)); + }) } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs b/substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs new file mode 100644 index 000000000000..1af1c94177d2 --- /dev/null +++ b/substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs @@ -0,0 +1,146 @@ +// 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. + +//! Autogenerated weights for `pallet_asset_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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-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 +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_asset_tx_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/transaction-payment/asset-tx-payment/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_asset_tx_payment`. +pub trait WeightInfo { + fn charge_asset_tx_payment_zero() -> Weight; + fn charge_asset_tx_payment_native() -> Weight; + fn charge_asset_tx_payment_asset() -> Weight; +} + +/// Weights for `pallet_asset_tx_payment` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 542_000 picoseconds. + Weight::from_parts(597_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`) + fn charge_asset_tx_payment_native() -> Weight { + // Proof Size summary in bytes: + // Measured: `248` + // Estimated: `1733` + // Minimum execution time: 33_162_000 picoseconds. + Weight::from_parts(34_716_000, 1733) + .saturating_add(T::DbWeight::get().reads(3_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:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, 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: `747` + // Estimated: `3675` + // Minimum execution time: 44_230_000 picoseconds. + Weight::from_parts(45_297_000, 3675) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 542_000 picoseconds. + Weight::from_parts(597_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`) + fn charge_asset_tx_payment_native() -> Weight { + // Proof Size summary in bytes: + // Measured: `248` + // Estimated: `1733` + // Minimum execution time: 33_162_000 picoseconds. + Weight::from_parts(34_716_000, 1733) + .saturating_add(RocksDbWeight::get().reads(3_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:1 w:1) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, 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: `747` + // Estimated: `3675` + // Minimum execution time: 44_230_000 picoseconds. + Weight::from_parts(45_297_000, 3675) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } +} 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 3ab38743bafd..dd907f6fcbb7 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/lib.rs @@ -21,7 +21,7 @@ //! //! ## Overview //! -//! It does this by wrapping an existing [`SignedExtension`] implementation (e.g. +//! It does this by wrapping an existing [`TransactionExtension`] implementation (e.g. //! [`pallet-transaction-payment`]) and checking if the dispatchable is feeless before applying the //! wrapped extension. If the dispatchable is indeed feeless, the extension is skipped and a custom //! event is emitted instead. Otherwise, the extension is applied as usual. @@ -31,7 +31,7 @@ //! //! This pallet wraps an existing transaction payment pallet. This means you should both pallets //! in your [`construct_runtime`](frame_support::construct_runtime) macro and -//! include this pallet's [`SignedExtension`] ([`SkipCheckIfFeeless`]) that would accept the +//! include this pallet's [`TransactionExtension`] ([`SkipCheckIfFeeless`]) that would accept the //! existing one as an argument. #![cfg_attr(not(feature = "std"), no_std)] @@ -39,12 +39,16 @@ use codec::{Decode, Encode}; use frame_support::{ dispatch::{CheckIfFeeless, DispatchResult}, + pallet_prelude::TransactionSource, traits::{IsType, OriginTrait}, + weights::Weight, }; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - traits::{DispatchInfoOf, PostDispatchInfoOf, SignedExtension}, - transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction}, + traits::{ + DispatchInfoOf, DispatchOriginOf, PostDispatchInfoOf, TransactionExtension, ValidateResult, + }, + transaction_validity::TransactionValidityError, }; #[cfg(test)] @@ -71,11 +75,11 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// A transaction fee was skipped. - FeeSkipped { who: T::AccountId }, + FeeSkipped { origin: ::PalletsOrigin }, } } -/// A [`SignedExtension`] that skips the wrapped extension if the dispatchable is feeless. +/// A [`TransactionExtension`] that skips the wrapped extension if the dispatchable is feeless. #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct SkipCheckIfFeeless(pub S, core::marker::PhantomData); @@ -104,67 +108,91 @@ impl From for SkipCheckIfFeeless { } } -impl> SignedExtension - for SkipCheckIfFeeless +pub enum Intermediate { + /// The wrapped extension should be applied. + Apply(T), + /// The wrapped extension should be skipped. + Skip(O), +} +use Intermediate::*; + +impl> + TransactionExtension for SkipCheckIfFeeless where - S::Call: CheckIfFeeless>, + T::RuntimeCall: CheckIfFeeless>, { - type AccountId = T::AccountId; - type Call = S::Call; - type AdditionalSigned = S::AdditionalSigned; - type Pre = (Self::AccountId, Option<::Pre>); // From the outside this extension should be "invisible", because it just extends the wrapped // extension with an extra check in `pre_dispatch` and `post_dispatch`. Thus, we should forward // the identifier of the wrapped extension to let wallets see this extension as it would only be // the wrapped extension itself. const IDENTIFIER: &'static str = S::IDENTIFIER; + type Implicit = S::Implicit; + + fn implicit(&self) -> Result { + self.0.implicit() + } + type Val = + Intermediate as OriginTrait>::PalletsOrigin>; + type Pre = + Intermediate as OriginTrait>::PalletsOrigin>; - fn additional_signed(&self) -> Result { - self.0.additional_signed() + fn weight(&self, call: &T::RuntimeCall) -> frame_support::weights::Weight { + self.0.weight(call) } fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + origin: DispatchOriginOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { - if call.is_feeless(&::RuntimeOrigin::signed(who.clone())) { - Ok(ValidTransaction::default()) + 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 { - self.0.validate(who, call, info, len) + let (x, y, z) = self.0.validate( + origin, + call, + info, + len, + self_implicit, + inherited_implication, + source, + )?; + Ok((x, Apply(y), z)) } } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + val: Self::Val, + origin: &DispatchOriginOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, ) -> Result { - if call.is_feeless(&::RuntimeOrigin::signed(who.clone())) { - Ok((who.clone(), None)) - } else { - Ok((who.clone(), Some(self.0.pre_dispatch(who, call, info, len)?))) + match val { + Apply(val) => self.0.prepare(val, origin, call, info, len).map(Apply), + Skip(origin) => Ok(Skip(origin)), } } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - if let Some(pre) = pre { - if let Some(pre) = pre.1 { - S::post_dispatch(Some(pre), info, post_info, len, result)?; - } else { - Pallet::::deposit_event(Event::::FeeSkipped { who: pre.0 }); - } + ) -> Result { + match pre { + Apply(pre) => S::post_dispatch_details(pre, info, post_info, len, result), + Skip(origin) => { + Pallet::::deposit_event(Event::::FeeSkipped { origin }); + Ok(Weight::zero()) + }, } - Ok(()) } } 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 d6d600f24e77..cff232a0cae3 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/mock.rs @@ -18,9 +18,12 @@ use crate as pallet_skip_feeless_payment; use frame_support::{derive_impl, parameter_types}; use frame_system as system; +use sp_runtime::{ + traits::{DispatchOriginOf, TransactionExtension}, + transaction_validity::ValidTransaction, +}; type Block = frame_system::mocking::MockBlock; -type AccountId = u64; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { @@ -32,42 +35,46 @@ impl Config for Runtime { } parameter_types! { - pub static PreDispatchCount: u32 = 0; + pub static PrepareCount: u32 = 0; pub static ValidateCount: u32 = 0; } #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)] pub struct DummyExtension; -impl SignedExtension for DummyExtension { - type AccountId = AccountId; - type Call = RuntimeCall; - type AdditionalSigned = (); - type Pre = (); +impl TransactionExtension for DummyExtension { const IDENTIFIER: &'static str = "DummyExtension"; - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) + type Implicit = (); + type Val = (); + type Pre = (); + + fn weight(&self, _: &RuntimeCall) -> Weight { + Weight::zero() } fn validate( &self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, + origin: DispatchOriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> ValidateResult { ValidateCount::mutate(|c| *c += 1); - Ok(Default::default()) + Ok((ValidTransaction::default(), (), origin)) } - fn pre_dispatch( + fn prepare( self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, + _val: Self::Val, + _origin: &DispatchOriginOf, + _call: &RuntimeCall, + _info: &DispatchInfoOf, _len: usize, ) -> Result { - PreDispatchCount::mutate(|c| *c += 1); + PrepareCount::mutate(|c| *c += 1); Ok(()) } } 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 adee52d6b3ce..b6ecbf9d5764 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/skip-feeless-payment/src/tests.rs @@ -15,23 +15,24 @@ use super::*; use crate::mock::{ - pallet_dummy::Call, DummyExtension, PreDispatchCount, Runtime, RuntimeCall, ValidateCount, + pallet_dummy::Call, DummyExtension, PrepareCount, Runtime, RuntimeCall, ValidateCount, }; use frame_support::dispatch::DispatchInfo; +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) - .pre_dispatch(&0, &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); - assert_eq!(PreDispatchCount::get(), 1); + assert_eq!(PrepareCount::get(), 1); let call = RuntimeCall::DummyPallet(Call::::aux { data: 0 }); SkipCheckIfFeeless::::from(DummyExtension) - .pre_dispatch(&0, &call, &DispatchInfo::default(), 0) + .validate_and_prepare(Some(0).into(), &call, &DispatchInfo::default(), 0, 0) .unwrap(); - assert_eq!(PreDispatchCount::get(), 1); + assert_eq!(PrepareCount::get(), 1); } #[test] @@ -40,13 +41,56 @@ fn validate_works() { let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); SkipCheckIfFeeless::::from(DummyExtension) - .validate(&0, &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(&0, &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); +} + +#[test] +fn validate_prepare_works() { + assert_eq!(ValidateCount::get(), 0); + + let call = RuntimeCall::DummyPallet(Call::::aux { data: 1 }); + SkipCheckIfFeeless::::from(DummyExtension) + .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, 0) + .unwrap(); + assert_eq!(ValidateCount::get(), 1); + assert_eq!(PrepareCount::get(), 1); + + // 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, 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 new file mode 100644 index 000000000000..eba4c0964ce7 --- /dev/null +++ b/substrate/frame/transaction-payment/src/benchmarking.rs @@ -0,0 +1,86 @@ +// 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. + +//! Benchmarks for Transaction Payment Pallet's transaction extension + +extern crate alloc; + +use super::*; +use crate::Pallet; +use frame_benchmarking::v2::*; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_system::{EventRecord, RawOrigin}; +use sp_runtime::traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable}; + +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 EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +#[benchmarks(where + T: Config, + T::RuntimeOrigin: AsTransactionAuthorizedOrigin, + T::RuntimeCall: Dispatchable, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn charge_transaction_payment() { + let caller: T::AccountId = account("caller", 0, 0); + >::endow_account( + &caller, + >::minimum_balance() * 1000u32.into(), + ); + let tip = >::minimum_balance(); + let ext: ChargeTransactionPayment = ChargeTransactionPayment::from(tip); + let inner = frame_system::Call::remark { remark: alloc::vec![] }; + let call = T::RuntimeCall::from(inner); + let extension_weight = ext.weight(&call); + let info = DispatchInfo { + call_weight: Weight::from_parts(100, 0), + extension_weight, + class: DispatchClass::Operational, + pays_fee: Pays::Yes, + }; + let mut post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(10, 0)), + pays_fee: Pays::Yes, + }; + + #[block] + { + assert!(ext + .test_run(RawOrigin::Signed(caller.clone()).into(), &call, &info, 10, 0, |_| Ok( + post_info + )) + .unwrap() + .is_ok()); + } + + post_info.actual_weight.as_mut().map(|w| w.saturating_accrue(extension_weight)); + let actual_fee = Pallet::::compute_actual_fee(10, &info, &post_info, tip); + assert_last_event::( + Event::::TransactionFeePaid { who: caller, actual_fee, tip }.into(), + ); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Runtime); +} diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index c17ab393b5d3..216697beac69 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -54,30 +54,35 @@ use frame_support::{ dispatch::{ DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo, }, + pallet_prelude::TransactionSource, traits::{Defensive, EstimateCallFee, Get}, weights::{Weight, WeightToFee}, + RuntimeDebugNoBound, }; pub use pallet::*; pub use payment::*; use sp_runtime::{ traits::{ Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion, - Saturating, SignedExtension, Zero, - }, - transaction_validity::{ - TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, + Saturating, TransactionExtension, Zero, }, + transaction_validity::{TransactionPriority, TransactionValidityError, ValidTransaction}, FixedPointNumber, FixedU128, Perbill, Perquintill, RuntimeDebug, }; pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; +pub use weights::WeightInfo; #[cfg(test)] mod mock; #[cfg(test)] mod tests; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + mod payment; mod types; +pub mod weights; /// Fee multiplier. pub type Multiplier = FixedU128; @@ -334,6 +339,7 @@ pub mod pallet { type RuntimeEvent = (); type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = (); + type WeightInfo = (); } } @@ -386,6 +392,9 @@ pub mod pallet { /// transactions. #[pallet::constant] type OperationalFeeMultiplier: Get; + + /// The weight information of this pallet. + type WeightInfo: WeightInfo; } #[pallet::type_value] @@ -394,6 +403,7 @@ pub mod pallet { } #[pallet::storage] + #[pallet::whitelist_storage] pub type NextFeeMultiplier = StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>; @@ -496,7 +506,7 @@ impl Pallet { /// /// All dispatchables must be annotated with weight and will have some fee info. This function /// always returns. - pub fn query_info( + pub fn query_info( unchecked_extrinsic: Extrinsic, len: u32, ) -> RuntimeDispatchInfo> @@ -510,20 +520,20 @@ impl Pallet { // a very very little potential gain in the future. let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); - let partial_fee = if unchecked_extrinsic.is_signed().unwrap_or(false) { - Self::compute_fee(len, &dispatch_info, 0u32.into()) - } else { - // Unsigned extrinsics have no partial fee. + let partial_fee = if unchecked_extrinsic.is_bare() { + // Bare extrinsics have no partial fee. 0u32.into() + } else { + Self::compute_fee(len, &dispatch_info, 0u32.into()) }; - let DispatchInfo { weight, class, .. } = dispatch_info; + let DispatchInfo { class, .. } = dispatch_info; - RuntimeDispatchInfo { weight, class, partial_fee } + RuntimeDispatchInfo { weight: dispatch_info.total_weight(), class, partial_fee } } /// Query the detailed fee of a given `call`. - pub fn query_fee_details( + pub fn query_fee_details( unchecked_extrinsic: Extrinsic, len: u32, ) -> FeeDetails> @@ -534,11 +544,11 @@ impl Pallet { let tip = 0u32.into(); - if unchecked_extrinsic.is_signed().unwrap_or(false) { - Self::compute_fee_details(len, &dispatch_info, tip) - } else { - // Unsigned extrinsics have no inclusion fee. + if unchecked_extrinsic.is_bare() { + // Bare extrinsics have no inclusion fee. FeeDetails { inclusion_fee: None, tip } + } else { + Self::compute_fee_details(len, &dispatch_info, tip) } } @@ -548,10 +558,10 @@ impl Pallet { T::RuntimeCall: Dispatchable + GetDispatchInfo, { let dispatch_info = ::get_dispatch_info(&call); - let DispatchInfo { weight, class, .. } = dispatch_info; + let DispatchInfo { class, .. } = dispatch_info; RuntimeDispatchInfo { - weight, + weight: dispatch_info.total_weight(), class, partial_fee: Self::compute_fee(len, &dispatch_info, 0u32.into()), } @@ -589,7 +599,7 @@ impl Pallet { where T::RuntimeCall: Dispatchable, { - Self::compute_fee_raw(len, info.weight, tip, info.pays_fee, info.class) + Self::compute_fee_raw(len, info.total_weight(), tip, info.pays_fee, info.class) } /// Compute the actual post dispatch fee for a particular transaction. @@ -722,7 +732,7 @@ where who: &T::AccountId, call: &T::RuntimeCall, info: &DispatchInfoOf, - len: usize, + fee: BalanceOf, ) -> Result< ( BalanceOf, @@ -731,7 +741,6 @@ where TransactionValidityError, > { let tip = self.0; - let fee = Pallet::::compute_fee(len as u32, info, tip); <::OnChargeTransaction as OnChargeTransaction>::withdraw_fee( who, call, info, fee, tip, @@ -739,6 +748,22 @@ where .map(|i| (fee, i)) } + fn can_withdraw_fee( + &self, + who: &T::AccountId, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + len: usize, + ) -> Result, TransactionValidityError> { + let tip = self.0; + let fee = Pallet::::compute_fee(len as u32, info, tip); + + <::OnChargeTransaction as OnChargeTransaction>::can_withdraw_fee( + who, call, info, fee, tip, + )?; + Ok(fee) + } + /// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length /// and user-included tip. /// @@ -764,7 +789,8 @@ where let max_block_length = *T::BlockLength::get().max.get(info.class) as u64; // bounded_weight is used as a divisor later so we keep it non-zero. - let bounded_weight = info.weight.max(Weight::from_parts(1, 1)).min(max_block_weight); + let bounded_weight = + info.total_weight().max(Weight::from_parts(1, 1)).min(max_block_weight); let bounded_length = (len as u64).clamp(1, max_block_length); // returns the scarce resource, i.e. the one that is limiting the number of transactions. @@ -825,68 +851,131 @@ impl core::fmt::Debug for ChargeTransactionPayment { } } -impl SignedExtension for ChargeTransactionPayment +/// The info passed between the validate and prepare steps for the `ChargeAssetTxPayment` extension. +#[derive(RuntimeDebugNoBound)] +pub enum Val { + Charge { + tip: BalanceOf, + // who paid the fee + who: T::AccountId, + // transaction fee + fee: BalanceOf, + }, + NoCharge, +} + +/// The info passed between the prepare and post-dispatch steps for the `ChargeAssetTxPayment` +/// extension. +pub enum Pre { + Charge { + tip: BalanceOf, + // who paid the fee + who: T::AccountId, + // imbalance resulting from withdrawing the fee + imbalance: <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, + }, + NoCharge { + // weight initially estimated by the extension, to be refunded + refund: Weight, + }, +} + +impl core::fmt::Debug for Pre { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + match self { + Pre::Charge { tip, who, imbalance: _ } => { + write!(f, "Charge {{ tip: {:?}, who: {:?}, imbalance: }}", tip, who) + }, + Pre::NoCharge { refund } => write!(f, "NoCharge {{ refund: {:?} }}", refund), + } + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.write_str("") + } +} + +impl TransactionExtension for ChargeTransactionPayment where - BalanceOf: Send + Sync + From, T::RuntimeCall: Dispatchable, { const IDENTIFIER: &'static str = "ChargeTransactionPayment"; - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); - type Pre = ( - // tip - BalanceOf, - // who paid the fee - this is an option to allow for a Default impl. - Self::AccountId, - // imbalance resulting from withdrawing the fee - <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, - ); - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) + type Implicit = (); + type Val = Val; + type Pre = Pre; + + fn weight(&self, _: &T::RuntimeCall) -> Weight { + T::WeightInfo::charge_transaction_payment() } fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, - ) -> TransactionValidity { - let (final_fee, _) = self.withdraw_fee(who, call, info, len)?; + _: (), + _implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + let Ok(who) = frame_system::ensure_signed(origin.clone()) else { + return Ok((ValidTransaction::default(), Val::NoCharge, origin)); + }; + let final_fee = self.can_withdraw_fee(&who, call, info, len)?; let tip = self.0; - Ok(ValidTransaction { - priority: Self::get_priority(info, len, tip, final_fee), - ..Default::default() - }) + Ok(( + ValidTransaction { + priority: Self::get_priority(info, len, tip, final_fee), + ..Default::default() + }, + Val::Charge { tip: self.0, who, fee: final_fee }, + origin, + )) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, + val: Self::Val, + _origin: &::RuntimeOrigin, + call: &T::RuntimeCall, + info: &DispatchInfoOf, + _len: usize, ) -> Result { - let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?; - Ok((self.0, who.clone(), imbalance)) + match val { + Val::Charge { tip, who, fee } => { + // Mutating call to `withdraw_fee` to actually charge for the transaction. + let (_final_fee, imbalance) = self.withdraw_fee(&who, call, info, fee)?; + Ok(Pre::Charge { tip, who, imbalance }) + }, + Val::NoCharge => Ok(Pre::NoCharge { refund: self.weight(call) }), + } } - fn post_dispatch( - maybe_pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, imbalance)) = maybe_pre { - let actual_fee = Pallet::::compute_actual_fee(len as u32, info, post_info, tip); - T::OnChargeTransaction::correct_and_deposit_fee( - &who, info, post_info, actual_fee, tip, imbalance, - )?; - Pallet::::deposit_event(Event::::TransactionFeePaid { who, actual_fee, tip }); - } - Ok(()) + ) -> Result { + let (tip, who, imbalance) = match pre { + Pre::Charge { tip, who, imbalance } => (tip, who, imbalance), + Pre::NoCharge { refund } => { + // No-op: Refund everything + return Ok(refund) + }, + }; + let actual_fee = Pallet::::compute_actual_fee(len as u32, info, &post_info, tip); + T::OnChargeTransaction::correct_and_deposit_fee( + &who, info, &post_info, actual_fee, tip, imbalance, + )?; + Pallet::::deposit_event(Event::::TransactionFeePaid { who, actual_fee, tip }); + Ok(Weight::zero()) } } diff --git a/substrate/frame/transaction-payment/src/mock.rs b/substrate/frame/transaction-payment/src/mock.rs index 8767024ee235..3995c41e8b19 100644 --- a/substrate/frame/transaction-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/src/mock.rs @@ -119,6 +119,15 @@ impl OnUnbalanced::AccountId, } } +/// Weights used in testing. +pub struct MockWeights; + +impl WeightInfo for MockWeights { + fn charge_transaction_payment() -> Weight { + Weight::from_parts(10, 0) + } +} + impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = FungibleAdapter; @@ -126,4 +135,14 @@ impl Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; type FeeMultiplierUpdate = (); + type WeightInfo = MockWeights; +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn new_test_ext() -> sp_io::TestExternalities { + crate::tests::ExtBuilder::default() + .base_weight(Weight::from_parts(100, 0)) + .byte_fee(10) + .balance_factor(0) + .build() } diff --git a/substrate/frame/transaction-payment/src/payment.rs b/substrate/frame/transaction-payment/src/payment.rs index 0fe616782903..4b39cd3fe53b 100644 --- a/substrate/frame/transaction-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/src/payment.rs @@ -20,14 +20,14 @@ use crate::Config; use core::marker::PhantomData; use sp_runtime::{ - traits::{DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, + traits::{CheckedSub, DispatchInfoOf, PostDispatchInfoOf, Saturating, Zero}, transaction_validity::InvalidTransaction, }; use frame_support::{ traits::{ fungible::{Balanced, Credit, Debt, Inspect}, - tokens::Precision, + tokens::{Precision, WithdrawConsequence}, Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReasons, }, unsigned::TransactionValidityError, @@ -55,6 +55,17 @@ pub trait OnChargeTransaction { tip: Self::Balance, ) -> Result; + /// Check if the predicted fee from the transaction origin can be withdrawn. + /// + /// Note: The `fee` already includes the `tip`. + fn can_withdraw_fee( + who: &T::AccountId, + call: &T::RuntimeCall, + dispatch_info: &DispatchInfoOf, + fee: Self::Balance, + tip: Self::Balance, + ) -> Result<(), TransactionValidityError>; + /// After the transaction was executed the actual fee can be calculated. /// This function should refund any overpaid fees and optionally deposit /// the corrected amount. @@ -68,6 +79,12 @@ pub trait OnChargeTransaction { tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, ) -> Result<(), TransactionValidityError>; + + #[cfg(feature = "runtime-benchmarks")] + fn endow_account(who: &T::AccountId, amount: Self::Balance); + + #[cfg(feature = "runtime-benchmarks")] + fn minimum_balance() -> Self::Balance; } /// Implements transaction payment for a pallet implementing the [`frame_support::traits::fungible`] @@ -110,6 +127,23 @@ where } } + fn can_withdraw_fee( + who: &T::AccountId, + _call: &T::RuntimeCall, + _dispatch_info: &DispatchInfoOf, + fee: Self::Balance, + _tip: Self::Balance, + ) -> Result<(), TransactionValidityError> { + if fee.is_zero() { + return Ok(()) + } + + match F::can_withdraw(who, fee) { + WithdrawConsequence::Success => Ok(()), + _ => Err(InvalidTransaction::Payment.into()), + } + } + fn correct_and_deposit_fee( who: &::AccountId, _dispatch_info: &DispatchInfoOf<::RuntimeCall>, @@ -141,6 +175,16 @@ where Ok(()) } + + #[cfg(feature = "runtime-benchmarks")] + fn endow_account(who: &T::AccountId, amount: Self::Balance) { + let _ = F::deposit(who, amount, Precision::BestEffort); + } + + #[cfg(feature = "runtime-benchmarks")] + fn minimum_balance() -> Self::Balance { + F::minimum_balance() + } } /// Implements the transaction payment for a pallet implementing the [`Currency`] @@ -202,6 +246,33 @@ where } } + /// Check if the predicted fee from the transaction origin can be withdrawn. + /// + /// Note: The `fee` already includes the `tip`. + fn can_withdraw_fee( + who: &T::AccountId, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + fee: Self::Balance, + tip: Self::Balance, + ) -> Result<(), TransactionValidityError> { + if fee.is_zero() { + return Ok(()) + } + + let withdraw_reason = if tip.is_zero() { + WithdrawReasons::TRANSACTION_PAYMENT + } else { + WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP + }; + + let new_balance = + C::free_balance(who).checked_sub(&fee).ok_or(InvalidTransaction::Payment)?; + C::ensure_can_withdraw(who, fee, withdraw_reason, new_balance) + .map(|_| ()) + .map_err(|_| InvalidTransaction::Payment.into()) + } + /// Hand the fee and the tip over to the `[OnUnbalanced]` implementation. /// Since the predicted fee might have been too high, parts of the fee may /// be refunded. @@ -234,4 +305,14 @@ where } Ok(()) } + + #[cfg(feature = "runtime-benchmarks")] + fn endow_account(who: &T::AccountId, amount: Self::Balance) { + let _ = C::deposit_creating(who, amount); + } + + #[cfg(feature = "runtime-benchmarks")] + fn minimum_balance() -> Self::Balance { + C::minimum_balance() + } } diff --git a/substrate/frame/transaction-payment/src/tests.rs b/substrate/frame/transaction-payment/src/tests.rs index bac89967d6af..572c1d4961dd 100644 --- a/substrate/frame/transaction-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/src/tests.rs @@ -21,13 +21,16 @@ use crate as pallet_transaction_payment; use codec::Encode; use sp_runtime::{ - testing::TestXt, traits::One, transaction_validity::InvalidTransaction, BuildStorage, + generic::UncheckedExtrinsic, + traits::{DispatchTransaction, One}, + transaction_validity::{InvalidTransaction, TransactionSource::External}, + BuildStorage, }; use frame_support::{ - assert_noop, assert_ok, + assert_ok, dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, - traits::Currency, + traits::{Currency, OriginTrait}, weights::Weight, }; use frame_system as system; @@ -113,7 +116,7 @@ impl ExtBuilder { /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { // pays_fee: Pays::Yes -- class: DispatchClass::Normal - DispatchInfo { weight: w, ..Default::default() } + DispatchInfo { call_weight: w, ..Default::default() } } fn post_info_from_weight(w: Weight) -> PostDispatchInfo { @@ -128,88 +131,82 @@ fn default_post_info() -> PostDispatchInfo { PostDispatchInfo { actual_weight: None, pays_fee: Default::default() } } +type Ext = ChargeTransactionPayment; + #[test] -fn signed_extension_transaction_payment_work() { +fn transaction_extension_transaction_payment_work() { ExtBuilder::default() .balance_factor(10) .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { - let len = 10; - let pre = ChargeTransactionPayment::::from(0) - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(5, 0)), len) - .unwrap(); - assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(5, 0)), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10); + let mut info = info_from_weight(Weight::from_parts(5, 0)); + 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, 0, |_| { + assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10 - 10); + Ok(default_post_info()) + }) + .unwrap() + .unwrap(); + assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10 - 10); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10 + 10); assert_eq!(TipUnbalancedAmount::get(), 0); FeeUnbalancedAmount::mutate(|a| *a = 0); - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) + 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, 0, |_| { + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 10 - 5); + Ok(post_info_from_weight(Weight::from_parts(50, 0))) + }) + .unwrap() .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(100, 0)), - &post_info_from_weight(Weight::from_parts(50, 0)), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); - assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50); + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 10 - 5); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50 + 10); assert_eq!(TipUnbalancedAmount::get(), 5); }); } #[test] -fn signed_extension_transaction_payment_multiplied_refund_works() { +fn transaction_extension_transaction_payment_multiplied_refund_works() { ExtBuilder::default() .balance_factor(10) .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { - let len = 10; NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) - .unwrap(); - // 5 base fee, 10 byte fee, 3/2 * 100 weight fee, 5 tip - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(100, 0)), - &post_info_from_weight(Weight::from_parts(50, 0)), - len, - &Ok(()) - )); - // 75 (3/2 of the returned 50 units of weight) is refunded - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 75 - 5); + let len = 10; + let origin = Some(2).into(); + let mut info = info_from_weight(Weight::from_parts(100, 0)); + let ext = Ext::from(5 /* tipped */); + let ext_weight = ext.weight(CALL); + info.extension_weight = ext_weight; + 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); + Ok(post_info_from_weight(Weight::from_parts(50, 0))) + }) + .unwrap() + .unwrap(); + + // 75 (3/2 of the returned 50 units of call weight, 0 returned of ext weight) is + // refunded + assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - (165 - 75) - 5); }); } #[test] -fn signed_extension_transaction_payment_is_bounded() { +fn transaction_extension_transaction_payment_is_bounded() { ExtBuilder::default().balance_factor(1000).byte_fee(0).build().execute_with(|| { // maximum weight possible - assert_ok!(ChargeTransactionPayment::::from(0).pre_dispatch( - &1, - CALL, - &info_from_weight(Weight::MAX), - 10 - )); + let info = info_from_weight(Weight::MAX); + 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), @@ -220,7 +217,7 @@ fn signed_extension_transaction_payment_is_bounded() { } #[test] -fn signed_extension_allows_free_transactions() { +fn transaction_extension_allows_free_transactions() { ExtBuilder::default() .base_weight(Weight::from_parts(100, 0)) .balance_factor(0) @@ -232,38 +229,32 @@ fn signed_extension_allows_free_transactions() { let len = 100; // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. - let operational_transaction = DispatchInfo { - weight: Weight::from_parts(0, 0), + let op_tx = DispatchInfo { + call_weight: Weight::from_parts(0, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::No, }; - assert_ok!(ChargeTransactionPayment::::from(0).validate( - &1, - CALL, - &operational_transaction, - len - )); + assert_ok!(Ext::from(0).validate_only(Some(1).into(), CALL, &op_tx, len, External, 0)); // like a InsecureFreeNormal - let free_transaction = DispatchInfo { - weight: Weight::from_parts(0, 0), + let free_tx = DispatchInfo { + call_weight: Weight::from_parts(0, 0), + extension_weight: Weight::zero(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - assert_noop!( - ChargeTransactionPayment::::from(0).validate( - &1, - CALL, - &free_transaction, - len - ), + assert_eq!( + Ext::from(0) + .validate_only(Some(1).into(), CALL, &free_tx, len, External, 0) + .unwrap_err(), TransactionValidityError::Invalid(InvalidTransaction::Payment), ); }); } #[test] -fn signed_ext_length_fee_is_also_updated_per_congestion() { +fn transaction_ext_length_fee_is_also_updated_per_congestion() { ExtBuilder::default() .base_weight(Weight::from_parts(5, 0)) .balance_factor(10) @@ -272,18 +263,15 @@ fn signed_ext_length_fee_is_also_updated_per_congestion() { // all fees should be x1.5 NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); let len = 10; - - assert_ok!( - ChargeTransactionPayment::::from(10) // tipped - .pre_dispatch(&1, CALL, &info_from_weight(Weight::from_parts(3, 0)), len) - ); + let info = info_from_weight(Weight::from_parts(3, 0)); + assert_ok!(Ext::from(10).validate_and_prepare(Some(1).into(), CALL, &info, len, 0)); assert_eq!( Balances::free_balance(1), 100 // original - - 10 // tip - - 5 // base - - 10 // len - - (3 * 3 / 2) // adjusted weight + - 10 // tip + - 5 // base + - 10 // len + - (3 * 3 / 2) // adjusted weight ); }) } @@ -293,62 +281,62 @@ fn query_info_and_fee_details_works() { let call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 2, value: 69 }); let origin = 111111; let extra = (); - let xt = TestXt::new(call.clone(), Some((origin, extra))); + let xt = UncheckedExtrinsic::new_signed(call.clone(), origin, (), extra); let info = xt.get_dispatch_info(); let ext = xt.encode(); let len = ext.len() as u32; - let unsigned_xt = TestXt::<_, ()>::new(call, None); + let unsigned_xt = UncheckedExtrinsic::::new_bare(call); let unsigned_xt_info = unsigned_xt.get_dispatch_info(); ExtBuilder::default() - .base_weight(Weight::from_parts(5, 0)) - .weight_fee(2) - .build() - .execute_with(|| { - // all fees should be x1.5 - NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); - - assert_eq!( - TransactionPayment::query_info(xt.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ - + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ - }, - ); - - assert_eq!( - TransactionPayment::query_info(unsigned_xt.clone(), len), - RuntimeDispatchInfo { - weight: unsigned_xt_info.weight, - class: unsigned_xt_info.class, - partial_fee: 0, - }, - ); - - assert_eq!( - TransactionPayment::query_fee_details(xt, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, - len_fee: len as u64, - adjusted_weight_fee: info - .weight - .min(BlockWeights::get().max_block) - .ref_time() as u64 * 2 * 3 / 2 - }), - tip: 0, - }, - ); - - assert_eq!( - TransactionPayment::query_fee_details(unsigned_xt, len), - FeeDetails { inclusion_fee: None, tip: 0 }, - ); - }); + .base_weight(Weight::from_parts(5, 0)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); + + assert_eq!( + TransactionPayment::query_info(xt.clone(), len), + RuntimeDispatchInfo { + weight: info.total_weight(), + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + + len as u64 /* len * 1 */ + + info.total_weight().min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ + }, + ); + + assert_eq!( + TransactionPayment::query_info(unsigned_xt.clone(), len), + RuntimeDispatchInfo { + weight: unsigned_xt_info.call_weight, + class: unsigned_xt_info.class, + partial_fee: 0, + }, + ); + + assert_eq!( + TransactionPayment::query_fee_details(xt, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, + len_fee: len as u64, + adjusted_weight_fee: info + .total_weight() + .min(BlockWeights::get().max_block) + .ref_time() as u64 * 2 * 3 / 2 + }), + tip: 0, + }, + ); + + assert_eq!( + TransactionPayment::query_fee_details(unsigned_xt, len), + FeeDetails { inclusion_fee: None, tip: 0 }, + ); + }); } #[test] @@ -359,39 +347,39 @@ fn query_call_info_and_fee_details_works() { let len = encoded_call.len() as u32; ExtBuilder::default() - .base_weight(Weight::from_parts(5, 0)) - .weight_fee(2) - .build() - .execute_with(|| { - // all fees should be x1.5 - NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); - - assert_eq!( - TransactionPayment::query_call_info(call.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ - + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ - }, - ); - - assert_eq!( - TransactionPayment::query_call_fee_details(call, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, /* base * weight_fee */ - len_fee: len as u64, /* len * 1 */ - adjusted_weight_fee: info - .weight - .min(BlockWeights::get().max_block) - .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multiplier */ - }), - tip: 0, - }, - ); - }); + .base_weight(Weight::from_parts(5, 0)) + .weight_fee(2) + .build() + .execute_with(|| { + // all fees should be x1.5 + NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); + + assert_eq!( + TransactionPayment::query_call_info(call.clone(), len), + RuntimeDispatchInfo { + weight: info.total_weight(), + class: info.class, + partial_fee: 5 * 2 /* base * weight_fee */ + + len as u64 /* len * 1 */ + + info.total_weight().min(BlockWeights::get().max_block).ref_time() as u64 * 2 * 3 / 2 /* weight */ + }, + ); + + assert_eq!( + TransactionPayment::query_call_fee_details(call, len), + FeeDetails { + inclusion_fee: Some(InclusionFee { + base_fee: 5 * 2, /* base * weight_fee */ + len_fee: len as u64, /* len * 1 */ + adjusted_weight_fee: info + .total_weight() + .min(BlockWeights::get().max_block) + .ref_time() as u64 * 2 * 3 / 2 /* weight * weight_fee * multipler */ + }), + tip: 0, + }, + ); + }); } #[test] @@ -407,14 +395,16 @@ fn compute_fee_works_without_multiplier() { // Tip only, no fees works let dispatch_info = DispatchInfo { - weight: Weight::from_parts(0, 0), + call_weight: Weight::from_parts(0, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::No, }; assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 10), 10); // No tip, only base fee works let dispatch_info = DispatchInfo { - weight: Weight::from_parts(0, 0), + call_weight: Weight::from_parts(0, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -425,7 +415,8 @@ fn compute_fee_works_without_multiplier() { assert_eq!(Pallet::::compute_fee(42, &dispatch_info, 0), 520); // Weight fee + base fee works let dispatch_info = DispatchInfo { - weight: Weight::from_parts(1000, 0), + call_weight: Weight::from_parts(1000, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -445,7 +436,8 @@ fn compute_fee_works_with_multiplier() { NextFeeMultiplier::::put(Multiplier::saturating_from_rational(3, 2)); // Base fee is unaffected by multiplier let dispatch_info = DispatchInfo { - weight: Weight::from_parts(0, 0), + call_weight: Weight::from_parts(0, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -453,7 +445,8 @@ fn compute_fee_works_with_multiplier() { // Everything works together :) let dispatch_info = DispatchInfo { - weight: Weight::from_parts(123, 0), + call_weight: Weight::from_parts(123, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -478,7 +471,8 @@ fn compute_fee_works_with_negative_multiplier() { // Base fee is unaffected by multiplier. let dispatch_info = DispatchInfo { - weight: Weight::from_parts(0, 0), + call_weight: Weight::from_parts(0, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -486,7 +480,8 @@ fn compute_fee_works_with_negative_multiplier() { // Everything works together. let dispatch_info = DispatchInfo { - weight: Weight::from_parts(123, 0), + call_weight: Weight::from_parts(123, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -508,7 +503,8 @@ fn compute_fee_does_not_overflow() { .execute_with(|| { // Overflow is handled let dispatch_info = DispatchInfo { - weight: Weight::MAX, + call_weight: Weight::MAX, + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; @@ -528,27 +524,23 @@ fn refund_does_not_recreate_account() { .execute_with(|| { // So events are emitted System::set_block_number(10); - let len = 10; - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) + let info = info_from_weight(Weight::from_parts(100, 0)); + Ext::from(5 /* tipped */) + .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 + assert_ok!(Balances::transfer_allow_death( + origin, + 3, + Balances::free_balance(2) + )); + assert_eq!(Balances::free_balance(2), 0); + + Ok(post_info_from_weight(Weight::from_parts(50, 0))) + }) + .unwrap() .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - // kill the account between pre and post dispatch - assert_ok!(Balances::transfer_allow_death( - Some(2).into(), - 3, - Balances::free_balance(2) - )); - assert_eq!(Balances::free_balance(2), 0); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(100, 0)), - &post_info_from_weight(Weight::from_parts(50, 0)), - len, - &Ok(()) - )); assert_eq!(Balances::free_balance(2), 0); // Transfer Event System::assert_has_event(RuntimeEvent::Balances(pallet_balances::Event::Transfer { @@ -570,20 +562,15 @@ fn actual_weight_higher_than_max_refunds_nothing() { .base_weight(Weight::from_parts(5, 0)) .build() .execute_with(|| { - let len = 10; - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_parts(100, 0)), len) + let info = info_from_weight(Weight::from_parts(100, 0)); + Ext::from(5 /* tipped */) + .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))) + }) + .unwrap() .unwrap(); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(Weight::from_parts(100, 0)), - &post_info_from_weight(Weight::from_parts(101, 0)), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); }); } @@ -596,25 +583,21 @@ fn zero_transfer_on_free_transaction() { .execute_with(|| { // So events are emitted System::set_block_number(10); - let len = 10; - let dispatch_info = DispatchInfo { - weight: Weight::from_parts(100, 0), + let info = DispatchInfo { + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), pays_fee: Pays::No, class: DispatchClass::Normal, }; let user = 69; - let pre = ChargeTransactionPayment::::from(0) - .pre_dispatch(&user, CALL, &dispatch_info, len) + Ext::from(0) + .test_run(Some(user).into(), CALL, &info, 10, 0, |_| { + assert_eq!(Balances::total_balance(&user), 0); + Ok(default_post_info()) + }) + .unwrap() .unwrap(); assert_eq!(Balances::total_balance(&user), 0); - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &dispatch_info, - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::total_balance(&user), 0); // TransactionFeePaid Event System::assert_has_event(RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { @@ -633,33 +616,33 @@ fn refund_consistent_with_actual_weight() { .base_weight(Weight::from_parts(7, 0)) .build() .execute_with(|| { - let info = info_from_weight(Weight::from_parts(100, 0)); - let post_info = post_info_from_weight(Weight::from_parts(33, 0)); + let mut info = info_from_weight(Weight::from_parts(100, 0)); + let tip = 5; + let ext = Ext::from(tip); + let ext_weight = ext.weight(CALL); + info.extension_weight = ext_weight; + let mut post_info = post_info_from_weight(Weight::from_parts(33, 0)); let prev_balance = Balances::free_balance(2); let len = 10; - let tip = 5; NextFeeMultiplier::::put(Multiplier::saturating_from_rational(5, 4)); - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) + let actual_post_info = ext + .test_run(Some(2).into(), CALL, &info, len, 0, |_| Ok(post_info)) + .unwrap() .unwrap(); - - ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info, - &post_info, - len, - &Ok(()), - ) - .unwrap(); + post_info + .actual_weight + .as_mut() + .map(|w| w.saturating_accrue(Ext::from(tip).weight(CALL))); + assert_eq!(post_info, actual_post_info); let refund_based_fee = prev_balance - Balances::free_balance(2); let actual_fee = - Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); + Pallet::::compute_actual_fee(len as u32, &info, &actual_post_info, tip); - // 33 weight, 10 length, 7 base, 5 tip - assert_eq!(actual_fee, 7 + 10 + (33 * 5 / 4) + 5); + // 33 call weight, 10 ext weight, 10 length, 7 base, 5 tip + assert_eq!(actual_fee, 7 + 10 + ((33 + 10) * 5 / 4) + 5); assert_eq!(refund_based_fee, actual_fee); }); } @@ -671,40 +654,50 @@ fn should_alter_operational_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) + + let ext = Ext::from(tip); + let priority = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) .unwrap() + .0 .priority; - assert_eq!(priority, 60); - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &normal, len) + let ext = Ext::from(2 * tip); + let priority = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) .unwrap() + .0 .priority; - assert_eq!(priority, 110); }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) + + let ext = Ext::from(tip); + let priority = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) .unwrap() + .0 .priority; assert_eq!(priority, 5810); - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &op, len) + let ext = Ext::from(2 * tip); + let priority = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) .unwrap() + .0 .priority; assert_eq!(priority, 6110); }); @@ -717,27 +710,32 @@ fn no_tip_has_some_priority() { ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) + let ext = Ext::from(tip); + let priority = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) .unwrap() + .0 .priority; - assert_eq!(priority, 10); }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) + let ext = Ext::from(tip); + let priority = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) .unwrap() + .0 .priority; assert_eq!(priority, 5510); }); @@ -746,34 +744,41 @@ fn no_tip_has_some_priority() { #[test] fn higher_tip_have_higher_priority() { let get_priorities = |tip: u64| { - let mut priority1 = 0; - let mut priority2 = 0; + let mut pri1 = 0; + let mut pri2 = 0; let len = 10; ExtBuilder::default().balance_factor(100).build().execute_with(|| { let normal = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }; - priority1 = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) + let ext = Ext::from(tip); + + pri1 = ext + .validate_only(Some(2).into(), CALL, &normal, len, External, 0) .unwrap() + .0 .priority; }); ExtBuilder::default().balance_factor(100).build().execute_with(|| { let op = DispatchInfo { - weight: Weight::from_parts(100, 0), + call_weight: Weight::from_parts(100, 0), + extension_weight: Weight::zero(), class: DispatchClass::Operational, pays_fee: Pays::Yes, }; - priority2 = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) + let ext = Ext::from(tip); + pri2 = ext + .validate_only(Some(2).into(), CALL, &op, len, External, 0) .unwrap() + .0 .priority; }); - (priority1, priority2) + (pri1, pri2) }; let mut prev_priorities = get_priorities(0); @@ -801,19 +806,11 @@ fn post_info_can_change_pays_fee() { NextFeeMultiplier::::put(Multiplier::saturating_from_rational(5, 4)); - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) + let post_info = ChargeTransactionPayment::::from(tip) + .test_run(Some(2).into(), CALL, &info, len, 0, |_| Ok(post_info)) + .unwrap() .unwrap(); - ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info, - &post_info, - len, - &Ok(()), - ) - .unwrap(); - let refund_based_fee = prev_balance - Balances::free_balance(2); let actual_fee = Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); @@ -843,3 +840,40 @@ fn genesis_default_works() { assert_eq!(NextFeeMultiplier::::get(), Multiplier::saturating_from_integer(1)); }); } + +#[test] +fn no_fee_and_no_weight_for_other_origins() { + ExtBuilder::default().build().execute_with(|| { + let ext = Ext::from(0); + + let mut info = CALL.get_dispatch_info(); + info.extension_weight = ext.weight(CALL); + + // Ensure we test the refund. + assert!(info.extension_weight != Weight::zero()); + + let len = CALL.encoded_size(); + + let origin = frame_system::RawOrigin::Root.into(); + let (pre, origin) = ext.validate_and_prepare(origin, CALL, &info, len, 0).unwrap(); + + assert!(origin.as_system_ref().unwrap().is_root()); + + let pd_res = Ok(()); + let mut post_info = frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(info.total_weight()), + pays_fee: Default::default(), + }; + + >::post_dispatch( + pre, + &info, + &mut post_info, + len, + &pd_res, + ) + .unwrap(); + + assert_eq!(post_info.actual_weight, Some(info.call_weight)); + }) +} diff --git a/substrate/frame/transaction-payment/src/types.rs b/substrate/frame/transaction-payment/src/types.rs index 67c7311d0cab..d6b4a6557447 100644 --- a/substrate/frame/transaction-payment/src/types.rs +++ b/substrate/frame/transaction-payment/src/types.rs @@ -111,7 +111,7 @@ pub struct RuntimeDispatchInfo /// The inclusion fee of this dispatch. /// /// This does not include a tip or anything else that - /// depends on the signature (i.e. depends on a `SignedExtension`). + /// depends on the signature (i.e. depends on a `TransactionExtension`). #[cfg_attr(feature = "std", serde(with = "serde_balance"))] pub partial_fee: Balance, } diff --git a/substrate/frame/transaction-payment/src/weights.rs b/substrate/frame/transaction-payment/src/weights.rs new file mode 100644 index 000000000000..59d5cac7a2b7 --- /dev/null +++ b/substrate/frame/transaction-payment/src/weights.rs @@ -0,0 +1,86 @@ +// 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. + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! 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: `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 +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/transaction-payment/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_transaction_payment`. +pub trait WeightInfo { + fn charge_transaction_payment() -> Weight; +} + +/// Weights for `pallet_transaction_payment` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +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`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // 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: `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: `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/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 55bdd4f7a498..93a3d9bea93d 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -30,6 +30,7 @@ frame-system = { workspace = true } pallet-balances = { workspace = true } sp-runtime = { workspace = true } sp-core = { optional = true, workspace = true } +log = { workspace = true } [dev-dependencies] sp-io = { workspace = true, default-features = true } @@ -43,6 +44,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-balances/std", "pallet-utility/std", "scale-info/std", diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index 650e5376fa4b..a03ee149db9b 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); diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index edb39f230642..faacda1c0783 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -73,6 +73,7 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +pub mod migration; #[cfg(test)] mod tests; pub mod weights; @@ -88,8 +89,11 @@ use scale_info::TypeInfo; use alloc::{boxed::Box, collections::btree_map::BTreeMap}; use sp_runtime::{ - traits::{AccountIdConversion, CheckedAdd, Saturating, StaticLookup, Zero}, - Permill, RuntimeDebug, + traits::{ + AccountIdConversion, BlockNumberProvider, CheckedAdd, One, Saturating, StaticLookup, + UniqueSaturatedInto, Zero, + }, + PerThing, Permill, RuntimeDebug, }; use frame_support::{ @@ -102,6 +106,7 @@ use frame_support::{ weights::Weight, BoundedVec, PalletId, }; +use frame_system::pallet_prelude::BlockNumberFor; pub use pallet::*; pub use weights::WeightInfo; @@ -235,6 +240,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,12 +282,21 @@ pub mod pallet { /// 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>; } + /// 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< @@ -295,6 +312,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 = ()> = @@ -321,6 +341,10 @@ pub mod pallet { OptionQuery, >; + /// The blocknumber for the last triggered spend period. + #[pallet::storage] + pub(crate) type LastSpendPeriod = StorageValue<_, BlockNumberFor, OptionQuery>; + #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig, I: 'static = ()> { @@ -413,7 +437,8 @@ pub mod pallet { impl, I: 'static> Hooks> for Pallet { /// ## Complexity /// - `O(A)` where `A` is the number of approvals - fn on_initialize(n: frame_system::pallet_prelude::BlockNumberFor) -> Weight { + fn on_initialize(_do_not_use_local_block_number: BlockNumberFor) -> Weight { + let block_number = T::BlockNumberProvider::current_block_number(); let pot = Self::pot(); let deactivated = Deactivated::::get(); if pot != deactivated { @@ -427,17 +452,29 @@ pub mod pallet { } // Check to see if we should spend some funds! - if (n % T::SpendPeriod::get()).is_zero() { - Self::spend_funds() + let last_spend_period = LastSpendPeriod::::get() + // This unwrap should only occur one time on any blockchain. + // `update_last_spend_period` will populate the `LastSpendPeriod` storage if it is + // 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()); + + // Safe because of `max(1)` above. + let (spend_periods_passed, extra_blocks) = ( + blocks_since_last_spend_period / safe_spend_period, + 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() { + Self::spend_funds(spend_periods_passed, new_last_spend_period) } else { Weight::zero() } } #[cfg(feature = "try-runtime")] - fn try_state( - _: frame_system::pallet_prelude::BlockNumberFor, - ) -> Result<(), sp_runtime::TryRuntimeError> { + fn try_state(_: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { Self::do_try_state()?; Ok(()) } @@ -469,6 +506,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, @@ -498,7 +539,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 { @@ -507,7 +550,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 }); @@ -537,12 +582,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); @@ -593,7 +643,7 @@ pub mod pallet { let max_amount = T::SpendOrigin::ensure_origin(origin)?; let beneficiary = T::BeneficiaryLookup::lookup(*beneficiary)?; - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); let valid_from = valid_from.unwrap_or(now); let expire_at = valid_from.saturating_add(T::PayoutPeriod::get()); ensure!(expire_at > now, Error::::SpendExpired); @@ -671,7 +721,7 @@ pub mod pallet { pub fn payout(origin: OriginFor, index: SpendIndex) -> DispatchResult { ensure_signed(origin)?; let mut spend = Spends::::get(index).ok_or(Error::::InvalidIndex)?; - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); ensure!(now >= spend.valid_from, Error::::EarlyPayout); ensure!(spend.expire_at > now, Error::::SpendExpired); ensure!( @@ -717,7 +767,7 @@ pub mod pallet { ensure_signed(origin)?; let mut spend = Spends::::get(index).ok_or(Error::::InvalidIndex)?; - let now = frame_system::Pallet::::block_number(); + let now = T::BlockNumberProvider::current_block_number(); if now > spend.expire_at && !matches!(spend.status, State::Attempted { .. }) { // spend has expired and no further status update is expected. @@ -791,23 +841,58 @@ impl, I: 'static> Pallet { T::PalletId::get().into_account_truncating() } + // 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 { + let block_number = T::BlockNumberProvider::current_block_number(); + 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. + let last_spend_period = if time_since_last_spend.is_zero() { + block_number.saturating_sub(spend_period) + } else { + // Otherwise, this is the last time we had a spend period. + block_number.saturating_sub(time_since_last_spend) + }; + LastSpendPeriod::::put(last_spend_period); + last_spend_period + } + /// 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() -> Weight { + pub fn spend_funds( + spend_periods_passed: BlockNumberFor, + new_last_spend_period: BlockNumberFor, + ) -> Weight { + LastSpendPeriod::::put(new_last_spend_period); let mut total_weight = Weight::zero(); let mut budget_remaining = Self::pot(); @@ -816,6 +901,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| { @@ -859,10 +945,15 @@ impl, I: 'static> Pallet { &mut missed_any, ); - if !missed_any { - // burn some proportion of the remaining budget if we run a surplus. - let burn = (T::Burn::get() * budget_remaining).min(budget_remaining); - budget_remaining -= burn; + if !missed_any && !T::Burn::get().is_zero() { + // Get the amount of treasury that should be left after potentially multiple spend + // periods have passed. + let one_minus_burn = T::Burn::get().left_from_one(); + let percent_left = + one_minus_burn.saturating_pow(spend_periods_passed.unique_saturated_into()); + let new_budget_remaining = percent_left * budget_remaining; + let burn = budget_remaining.saturating_sub(new_budget_remaining); + budget_remaining = new_budget_remaining; let (debit, credit) = T::Currency::pair(burn); imbalance.subsume(debit); diff --git a/substrate/frame/treasury/src/migration.rs b/substrate/frame/treasury/src/migration.rs new file mode 100644 index 000000000000..7c8c587f1664 --- /dev/null +++ b/substrate/frame/treasury/src/migration.rs @@ -0,0 +1,135 @@ +// 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. + +//! Treasury pallet migrations. + +use super::*; +use alloc::collections::BTreeSet; +#[cfg(feature = "try-runtime")] +use alloc::vec::Vec; +use core::marker::PhantomData; +use frame_support::{defensive, traits::OnRuntimeUpgrade}; + +/// The log target for this pallet. +const LOG_TARGET: &str = "runtime::treasury"; + +pub mod cleanup_proposals { + use super::*; + + /// Migration to cleanup unapproved proposals to return the bonds back to the proposers. + /// Proposals can no longer be created and the `Proposal` storage item will be removed in the + /// future. + /// + /// `UnreserveWeight` returns `Weight` of `unreserve_balance` operation which is perfomed during + /// this migration. + pub struct Migration(PhantomData<(T, I, UnreserveWeight)>); + + impl, I: 'static, UnreserveWeight: Get> OnRuntimeUpgrade + for Migration + { + 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); + if err_amount.is_zero() { + Proposals::::remove(proposal_index); + log::info!( + target: LOG_TARGET, + "Released bond amount of {:?} to proposer {:?}", + p.bond, + p.proposer, + ); + } else { + defensive!( + "err_amount is non zero for proposal {:?}", + (proposal_index, err_amount) + ); + Proposals::::mutate_extant(proposal_index, |proposal| { + proposal.value = err_amount; + }); + log::info!( + target: LOG_TARGET, + "Released partial bond amount of {:?} to proposer {:?}", + p.bond - err_amount, + p.proposer, + ); + } + proposals_processed += 1; + } + } + + log::info!( + target: LOG_TARGET, + "Migration for pallet-treasury finished, released {} proposal bonds.", + proposals_processed, + ); + + // calculate and return migration weights + let approvals_read = 1; + T::DbWeight::get().reads_writes( + proposals_processed as u64 + approvals_read, + proposals_processed as u64, + ) + UnreserveWeight::get() * proposals_processed + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let value = ( + Proposals::::iter_values().count() as u32, + Approvals::::get().len() as u32, + ); + log::info!( + target: LOG_TARGET, + "Proposals and Approvals count {:?}", + value, + ); + Ok(value.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let (old_proposals_count, old_approvals_count) = + <(u32, u32)>::decode(&mut &state[..]).expect("Known good"); + let new_proposals_count = Proposals::::iter_values().count() as u32; + let new_approvals_count = Approvals::::get().len() as u32; + + log::info!( + target: LOG_TARGET, + "Proposals and Approvals count {:?}", + (new_proposals_count, new_approvals_count), + ); + + ensure!( + new_proposals_count <= old_proposals_count, + "Proposals after migration should be less or equal to old proposals" + ); + ensure!( + new_approvals_count == old_approvals_count, + "Approvals after migration should remain the same" + ); + Ok(()) + } + } +} diff --git a/substrate/frame/treasury/src/tests.rs b/substrate/frame/treasury/src/tests.rs index 106bfb530a88..e9efb7c0956f 100644 --- a/substrate/frame/treasury/src/tests.rs +++ b/substrate/frame/treasury/src/tests.rs @@ -97,6 +97,12 @@ fn set_status(id: u64, s: PaymentStatus) { STATUS.with(|m| m.borrow_mut().insert(id, s)); } +// This function directly jumps to a block number, and calls `on_initialize`. +fn go_to_block(n: u64) { + ::BlockNumberProvider::set_block_number(n); + >::on_initialize(n); +} + pub struct TestPay; impl Pay for TestPay { type Beneficiary = u128; @@ -187,6 +193,7 @@ impl Config for Test { type Paymaster = TestPay; type BalanceConverter = MulBy>; type PayoutPeriod = SpendPayoutPeriod; + type BlockNumberProvider = System; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -242,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!( @@ -266,9 +274,10 @@ 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(), 101); + Balances::make_free_balance_be(&Treasury::account_id(), 102); // approve spend of some amount to beneficiary `6`. assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); assert_ok!(Treasury::spend_local(RuntimeOrigin::signed(10), 5, 6)); @@ -278,12 +287,12 @@ fn spend_local_origin_works() { 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. - >::on_initialize(1); + go_to_block(1); assert_eq!(Balances::free_balance(6), 0); // free balance of `6` is `100`, spend period has passed. - >::on_initialize(2); + go_to_block(2); assert_eq!(Balances::free_balance(6), 100); - // `100` spent, `1` burned. + // `100` spent, `1` burned, `1` in ED. assert_eq!(Treasury::pot(), 0); }); } @@ -302,9 +311,12 @@ 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)); + } - >::on_initialize(1); + go_to_block(1); assert_eq!(Balances::free_balance(3), 0); assert_eq!(Treasury::pot(), 100); }); @@ -317,7 +329,7 @@ fn unused_pot_should_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(pallet_balances::TotalIssuance::::get(), init_total_issuance + 100); - >::on_initialize(2); + go_to_block(2); assert_eq!(Treasury::pot(), 50); assert_eq!(pallet_balances::TotalIssuance::::get(), init_total_issuance + 50); }); @@ -329,9 +341,12 @@ 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)); + } - >::on_initialize(2); + go_to_block(2); assert_eq!(Balances::free_balance(3), 100); assert_eq!(Treasury::pot(), 0); }); @@ -343,13 +358,16 @@ 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)); + } - >::on_initialize(2); + go_to_block(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed let _ = Balances::deposit_into_existing(&Treasury::account_id(), 100).unwrap(); - >::on_initialize(4); + go_to_block(4); assert_eq!(Balances::free_balance(3), 150); // Fund has been spent assert_eq!(Treasury::pot(), 25); // Pot has finally changed }); @@ -363,15 +381,21 @@ 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)); - >::on_initialize(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)); + } - >::on_initialize(4); + go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied assert_eq!(Balances::free_balance(Treasury::account_id()), 1); // but the account is still there }); @@ -392,10 +416,14 @@ 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); - >::on_initialize(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed @@ -403,7 +431,7 @@ fn inexistent_account_works() { assert_eq!(Treasury::pot(), 99); // Pot now contains funds assert_eq!(Balances::free_balance(Treasury::account_id()), 100); // Account does exist - >::on_initialize(4); + go_to_block(4); assert_eq!(Treasury::pot(), 0); // Pot has changed assert_eq!(Balances::free_balance(3), 99); // Balance of `3` has changed @@ -431,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); @@ -449,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); @@ -788,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); @@ -808,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); @@ -838,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); @@ -936,3 +975,38 @@ fn try_state_spends_invariant_3_works() { ); }); } + +#[test] +fn multiple_spend_periods_work() { + ExtBuilder::default().build().execute_with(|| { + // Check that accumulate works when we have Some value in Dummy already. + // 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`. + #[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); + // free balance of `6` is `100`, spend period has passed. + go_to_block(2); + assert_eq!(Balances::free_balance(6), 100); + // `100` spent, 50% burned + assert_eq!(Treasury::pot(), 512); + + // 3 more spends periods pass at once, and an extra block. + go_to_block(2 + (3 * 2) + 1); + // Pot should be reduced by 50% 3 times, so 1/8th the amount. + assert_eq!(Treasury::pot(), 64); + // Even though we are on block 9, the last spend period was block 8. + assert_eq!(LastSpendPeriod::::get(), Some(8)); + }); +} 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/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/src/lib.rs b/substrate/frame/uniques/src/lib.rs index dc27c3356234..84f122c08bb7 100644 --- a/substrate/frame/uniques/src/lib.rs +++ b/substrate/frame/uniques/src/lib.rs @@ -223,7 +223,7 @@ pub mod pallet { #[pallet::storage] #[pallet::storage_prefix = "ClassMetadataOf"] /// Metadata of a collection. - pub(super) type CollectionMetadataOf, I: 'static = ()> = StorageMap< + pub type CollectionMetadataOf, I: 'static = ()> = StorageMap< _, Blake2_128Concat, T::CollectionId, @@ -234,7 +234,7 @@ pub mod pallet { #[pallet::storage] #[pallet::storage_prefix = "InstanceMetadataOf"] /// Metadata of an item. - pub(super) type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< + pub type ItemMetadataOf, I: 'static = ()> = StorageDoubleMap< _, Blake2_128Concat, T::CollectionId, diff --git a/substrate/frame/uniques/src/types.rs b/substrate/frame/uniques/src/types.rs index a2e804f245f7..e2e170c72f21 100644 --- a/substrate/frame/uniques/src/types.rs +++ b/substrate/frame/uniques/src/types.rs @@ -40,26 +40,26 @@ pub(super) type ItemPrice = #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct CollectionDetails { /// Can change `owner`, `issuer`, `freezer` and `admin` accounts. - pub(super) owner: AccountId, + pub owner: AccountId, /// Can mint tokens. - pub(super) issuer: AccountId, + pub issuer: AccountId, /// Can thaw tokens, force transfers and burn tokens from any account. - pub(super) admin: AccountId, + pub admin: AccountId, /// Can freeze tokens. - pub(super) freezer: AccountId, + pub freezer: AccountId, /// The total balance deposited for the all storage associated with this collection. /// Used by `destroy`. - pub(super) total_deposit: DepositBalance, + pub total_deposit: DepositBalance, /// If `true`, then no deposit is needed to hold items of this collection. - pub(super) free_holding: bool, + pub free_holding: bool, /// The total number of outstanding items of this collection. - pub(super) items: u32, + pub items: u32, /// The total number of outstanding item metadata of this collection. - pub(super) item_metadatas: u32, + pub item_metadatas: u32, /// The total number of attributes for this collection. - pub(super) attributes: u32, + pub attributes: u32, /// Whether the collection is frozen for non-admin transfers. - pub(super) is_frozen: bool, + pub is_frozen: bool, } /// Witness data for the destroy transactions. @@ -90,14 +90,14 @@ impl CollectionDetails { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] pub struct ItemDetails { /// The owner of this item. - pub(super) owner: AccountId, + pub owner: AccountId, /// The approved transferrer of this item, if one is set. - pub(super) approved: Option, + pub approved: Option, /// Whether the item can be transferred or not. - pub(super) is_frozen: bool, + pub is_frozen: bool, /// The amount held in the pallet's default account for this item. Free-hold items will have /// this as zero. - pub(super) deposit: DepositBalance, + pub deposit: DepositBalance, } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] @@ -107,13 +107,13 @@ pub struct CollectionMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. - pub(super) deposit: DepositBalance, + pub deposit: DepositBalance, /// General information concerning this collection. Limited in length by `StringLimit`. This /// will generally be either a JSON dump or the hash of some JSON which can be found on a /// hash-addressable global publication system such as IPFS. - pub(super) data: BoundedVec, + pub data: BoundedVec, /// Whether the collection's metadata may be changed by a non Force origin. - pub(super) is_frozen: bool, + pub is_frozen: bool, } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, TypeInfo, MaxEncodedLen)] @@ -123,11 +123,11 @@ pub struct ItemMetadata> { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. - pub(super) deposit: DepositBalance, + pub deposit: DepositBalance, /// General information concerning this item. Limited in length by `StringLimit`. This will /// generally be either a JSON dump or the hash of some JSON which can be found on a /// hash-addressable global publication system such as IPFS. - pub(super) data: BoundedVec, + pub data: BoundedVec, /// Whether the item metadata may be changed by a non Force origin. - pub(super) is_frozen: bool, + pub is_frozen: bool, } 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/src/benchmarking.rs b/substrate/frame/utility/src/benchmarking.rs index 467055ecd800..88556c05195a 100644 --- a/substrate/frame/utility/src/benchmarking.rs +++ b/substrate/frame/utility/src/benchmarking.rs @@ -19,73 +19,82 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; -use alloc::{vec, vec::Vec}; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use alloc::vec; +use frame_benchmarking::{benchmarking::add_to_whitelist, v2::*}; use frame_system::RawOrigin; +use crate::*; + const SEED: u32 = 0; fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -benchmarks! { - where_clause { where ::PalletsOrigin: Clone } - batch { - let c in 0 .. 1000; - let mut calls: Vec<::RuntimeCall> = Vec::new(); - for i in 0 .. c { - let call = frame_system::Call::remark { remark: vec![] }.into(); - calls.push(call); - } +#[benchmarks] +mod benchmark { + use super::*; + + #[benchmark] + fn batch(c: Linear<0, 1000>) { + let calls = vec![frame_system::Call::remark { remark: vec![] }.into(); c as usize]; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), calls) - verify { - assert_last_event::(Event::BatchCompleted.into()) + + #[extrinsic_call] + _(RawOrigin::Signed(caller), calls); + + assert_last_event::(Event::BatchCompleted.into()); } - as_derivative { + #[benchmark] + fn as_derivative() { let caller = account("caller", SEED, SEED); let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller), SEED as u16, call) - - batch_all { - let c in 0 .. 1000; - let mut calls: Vec<::RuntimeCall> = Vec::new(); - for i in 0 .. c { - let call = frame_system::Call::remark { remark: vec![] }.into(); - calls.push(call); - } + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), SEED as u16, call); + } + + #[benchmark] + fn batch_all(c: Linear<0, 1000>) { + let calls = vec![frame_system::Call::remark { remark: vec![] }.into(); c as usize]; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), calls) - verify { - assert_last_event::(Event::BatchCompleted.into()) + + #[extrinsic_call] + _(RawOrigin::Signed(caller), calls); + + assert_last_event::(Event::BatchCompleted.into()); } - dispatch_as { + #[benchmark] + fn dispatch_as() { let caller = account("caller", SEED, SEED); let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); - let origin: T::RuntimeOrigin = RawOrigin::Signed(caller).into(); - let pallets_origin: ::PalletsOrigin = origin.caller().clone(); - let pallets_origin = Into::::into(pallets_origin); - }: _(RawOrigin::Root, Box::new(pallets_origin), call) - - force_batch { - let c in 0 .. 1000; - let mut calls: Vec<::RuntimeCall> = Vec::new(); - for i in 0 .. c { - let call = frame_system::Call::remark { remark: vec![] }.into(); - calls.push(call); - } + let origin = T::RuntimeOrigin::from(RawOrigin::Signed(caller)); + let pallets_origin = origin.caller().clone(); + let pallets_origin = T::PalletsOrigin::from(pallets_origin); + + #[extrinsic_call] + _(RawOrigin::Root, Box::new(pallets_origin), call); + } + + #[benchmark] + fn force_batch(c: Linear<0, 1000>) { + let calls = vec![frame_system::Call::remark { remark: vec![] }.into(); c as usize]; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), calls) - verify { - assert_last_event::(Event::BatchCompleted.into()) + + #[extrinsic_call] + _(RawOrigin::Signed(caller), calls); + + assert_last_event::(Event::BatchCompleted.into()); } - impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); + impl_benchmark_test_suite! { + Pallet, + tests::new_test_ext(), + tests::Test + } } diff --git a/substrate/frame/utility/src/lib.rs b/substrate/frame/utility/src/lib.rs index a4f66298f3fa..26c38d1f0459 100644 --- a/substrate/frame/utility/src/lib.rs +++ b/substrate/frame/utility/src/lib.rs @@ -249,7 +249,7 @@ pub mod pallet { T::WeightInfo::as_derivative() // AccountData for inner call origin accountdata. .saturating_add(T::DbWeight::get().reads_writes(1, 1)) - .saturating_add(dispatch_info.weight), + .saturating_add(dispatch_info.call_weight), dispatch_info.class, ) })] @@ -354,7 +354,7 @@ pub mod pallet { let dispatch_info = call.get_dispatch_info(); ( T::WeightInfo::dispatch_as() - .saturating_add(dispatch_info.weight), + .saturating_add(dispatch_info.call_weight), dispatch_info.class, ) })] @@ -466,7 +466,7 @@ pub mod pallet { (Weight::zero(), DispatchClass::Operational), |(total_weight, dispatch_class): (Weight, DispatchClass), di| { ( - total_weight.saturating_add(di.weight), + total_weight.saturating_add(di.call_weight), // If not all are `Operational`, we want to use `DispatchClass::Normal`. if di.class == DispatchClass::Normal { di.class } else { dispatch_class }, ) diff --git a/substrate/frame/utility/src/tests.rs b/substrate/frame/utility/src/tests.rs index 9755efaea41a..274a90d77cf0 100644 --- a/substrate/frame/utility/src/tests.rs +++ b/substrate/frame/utility/src/tests.rs @@ -296,7 +296,7 @@ fn as_derivative_handles_weight_refund() { let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); - assert_eq!(extract_actual_weight(&result, &info), info.weight); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight); // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); @@ -308,7 +308,7 @@ fn as_derivative_handles_weight_refund() { let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded - assert_eq!(extract_actual_weight(&result, &info), info.weight - diff); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight - diff); // Full weight when err let inner_call = call_foobar(true, start_weight, None); @@ -323,7 +323,7 @@ fn as_derivative_handles_weight_refund() { DispatchErrorWithPostInfo { post_info: PostDispatchInfo { // No weight is refunded - actual_weight: Some(info.weight), + actual_weight: Some(info.call_weight), pays_fee: Pays::Yes, }, error: DispatchError::Other("The cake is a lie."), @@ -343,7 +343,7 @@ fn as_derivative_handles_weight_refund() { DispatchErrorWithPostInfo { post_info: PostDispatchInfo { // Diff is refunded - actual_weight: Some(info.weight - diff), + actual_weight: Some(info.call_weight - diff), pays_fee: Pays::Yes, }, error: DispatchError::Other("The cake is a lie."), @@ -456,14 +456,14 @@ fn batch_weight_calculation_doesnt_overflow() { let big_call = RuntimeCall::RootTesting(RootTestingCall::fill_block { ratio: Perbill::from_percent(50), }); - assert_eq!(big_call.get_dispatch_info().weight, Weight::MAX / 2); + assert_eq!(big_call.get_dispatch_info().call_weight, Weight::MAX / 2); // 3 * 50% saturates to 100% let batch_call = RuntimeCall::Utility(crate::Call::batch { calls: vec![big_call.clone(), big_call.clone(), big_call.clone()], }); - assert_eq!(batch_call.get_dispatch_info().weight, Weight::MAX); + assert_eq!(batch_call.get_dispatch_info().call_weight, Weight::MAX); }); } @@ -482,7 +482,7 @@ fn batch_handles_weight_refund() { let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); - assert_eq!(extract_actual_weight(&result, &info), info.weight); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight); // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); @@ -492,7 +492,7 @@ fn batch_handles_weight_refund() { let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded - assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight - diff * batch_len); // Full weight when err let good_call = call_foobar(false, start_weight, None); @@ -506,7 +506,7 @@ fn batch_handles_weight_refund() { utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), ); // No weight is refunded - assert_eq!(extract_actual_weight(&result, &info), info.weight); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight); // Refund weight when err let good_call = call_foobar(false, start_weight, Some(end_weight)); @@ -520,7 +520,7 @@ fn batch_handles_weight_refund() { System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), ); - assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight - diff * batch_len); // Partial batch completion let good_call = call_foobar(false, start_weight, Some(end_weight)); @@ -571,7 +571,7 @@ fn batch_all_revert() { DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some( - ::WeightInfo::batch_all(2) + info.weight * 2 + ::WeightInfo::batch_all(2) + info.call_weight * 2 ), pays_fee: Pays::Yes }, @@ -598,7 +598,7 @@ fn batch_all_handles_weight_refund() { let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); - assert_eq!(extract_actual_weight(&result, &info), info.weight); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight); // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); @@ -608,7 +608,7 @@ fn batch_all_handles_weight_refund() { let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded - assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight - diff * batch_len); // Full weight when err let good_call = call_foobar(false, start_weight, None); @@ -619,7 +619,7 @@ fn batch_all_handles_weight_refund() { let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); // No weight is refunded - assert_eq!(extract_actual_weight(&result, &info), info.weight); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight); // Refund weight when err let good_call = call_foobar(false, start_weight, Some(end_weight)); @@ -630,7 +630,7 @@ fn batch_all_handles_weight_refund() { let info = call.get_dispatch_info(); let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); - assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); + assert_eq!(extract_actual_weight(&result, &info), info.call_weight - diff * batch_len); // Partial batch completion let good_call = call_foobar(false, start_weight, Some(end_weight)); @@ -664,7 +664,9 @@ fn batch_all_does_not_nest() { Utility::batch_all(RuntimeOrigin::signed(1), vec![batch_all.clone()]), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { - actual_weight: Some(::WeightInfo::batch_all(1) + info.weight), + actual_weight: Some( + ::WeightInfo::batch_all(1) + info.call_weight + ), pays_fee: Pays::Yes }, error: frame_system::Error::::CallFiltered.into(), @@ -789,7 +791,7 @@ fn batch_all_doesnt_work_with_inherents() { batch_all.dispatch(RuntimeOrigin::signed(1)), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { - actual_weight: Some(info.weight), + actual_weight: Some(info.call_weight), pays_fee: Pays::Yes }, error: frame_system::Error::::CallFiltered.into(), @@ -805,7 +807,7 @@ fn batch_works_with_council_origin() { calls: vec![RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {})], }); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Council::propose( @@ -842,7 +844,7 @@ fn force_batch_works_with_council_origin() { calls: vec![RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {})], }); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); - let proposal_weight = proposal.get_dispatch_info().weight; + let proposal_weight = proposal.get_dispatch_info().call_weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Council::propose( @@ -892,7 +894,7 @@ fn with_weight_works() { })); // Weight before is max. assert_eq!( - upgrade_code_call.get_dispatch_info().weight, + upgrade_code_call.get_dispatch_info().call_weight, ::SystemWeightInfo::set_code() ); assert_eq!( @@ -905,7 +907,7 @@ fn with_weight_works() { weight: Weight::from_parts(123, 456), }; // Weight after is set by Root. - assert_eq!(with_weight_call.get_dispatch_info().weight, Weight::from_parts(123, 456)); + assert_eq!(with_weight_call.get_dispatch_info().call_weight, Weight::from_parts(123, 456)); assert_eq!( with_weight_call.get_dispatch_info().class, frame_support::dispatch::DispatchClass::Operational 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 new file mode 100644 index 000000000000..3c5fd5e65157 --- /dev/null +++ b/substrate/frame/verify-signature/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "pallet-verify-signature" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "FRAME verify signature pallet" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +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 } +sp-core = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +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-timestamp = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "pallet-balances/std", + "pallet-collective/std", + "pallet-root-testing/std", + "pallet-timestamp/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-weights/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-collective/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-collective/try-runtime", + "pallet-root-testing/try-runtime", + "pallet-timestamp/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/verify-signature/README.md b/substrate/frame/verify-signature/README.md new file mode 100644 index 000000000000..7748315c61cc --- /dev/null +++ b/substrate/frame/verify-signature/README.md @@ -0,0 +1,19 @@ +# Verify Signature Module +A module that provides a `TransactionExtension` that validates a signature against a payload and +authorizes the origin. + +## Overview + +This module serves two purposes: +- `VerifySignature`: A `TransactionExtension` that checks the provided signature against a payload + constructed through hashing the inherited implication with `blake2b_256`. If the signature is + valid, then the extension authorizes the origin as signed. The extension can be disabled, or + passthrough, allowing users to use other extensions to authorize different origins other than the + traditionally signed origin. +- Benchmarking: The extension is bound within a pallet to leverage the benchmarking functionality in + FRAME. The `Signature` and `Signer` types are specified in the pallet configuration and a + benchmark helper trait is used to create a signature which is then validated in the benchmark. + +[`Config`]: ./trait.Config.html + +License: Apache-2.0 diff --git a/substrate/frame/verify-signature/src/benchmarking.rs b/substrate/frame/verify-signature/src/benchmarking.rs new file mode 100644 index 000000000000..99e893e6f6ab --- /dev/null +++ b/substrate/frame/verify-signature/src/benchmarking.rs @@ -0,0 +1,81 @@ +// 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. + +//! Benchmarks for Verify Signature Pallet + +#![cfg(feature = "runtime-benchmarks")] + +extern crate alloc; + +use super::*; + +#[allow(unused)] +use crate::{extension::VerifySignature, Config, Pallet as VerifySignaturePallet}; +use alloc::vec; +use frame_benchmarking::{v2::*, BenchmarkError}; +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::{ + generic::ExtensionVersion, + traits::{AsTransactionAuthorizedOrigin, DispatchTransaction, Dispatchable}, +}; + +pub trait BenchmarkHelper { + fn create_signature(entropy: &[u8], msg: &[u8]) -> (Signature, Signer); +} + +#[benchmarks(where + T: Config + Send + Sync, + T::RuntimeCall: Dispatchable + GetDispatchInfo, + T::RuntimeOrigin: AsTransactionAuthorizedOrigin, +)] +mod benchmarks { + use super::*; + + #[benchmark] + 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 = (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_only( + RawOrigin::None.into(), + &call, + &info, + 0, + TransactionSource::External, + ext_version + ) + .is_ok()); + } + + Ok(()) + } + + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test); +} diff --git a/substrate/frame/verify-signature/src/extension.rs b/substrate/frame/verify-signature/src/extension.rs new file mode 100644 index 000000000000..d48991e7a1da --- /dev/null +++ b/substrate/frame/verify-signature/src/extension.rs @@ -0,0 +1,158 @@ +// 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. + +//! Transaction extension which validates a signature against a payload constructed from a call and +//! the rest of the transaction extension pipeline. + +use crate::{Config, WeightInfo}; +use codec::{Decode, Encode}; +use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait}; +use scale_info::TypeInfo; +use sp_io::hashing::blake2_256; +use sp_runtime::{ + impl_tx_ext_default, + traits::{ + transaction_extension::TransactionExtension, AsTransactionAuthorizedOrigin, DispatchInfoOf, + Dispatchable, Verify, + }, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransaction}, +}; +use sp_weights::Weight; + +/// Extension that, if enabled, validates a signature type against the payload constructed from the +/// call and the rest of the transaction extension pipeline. This extension provides the +/// functionality that traditionally signed transactions had with the implicit signature checking +/// implemented in [`Checkable`](sp_runtime::traits::Checkable). It is meant to be placed ahead of +/// any other extensions that do authorization work in the [`TransactionExtension`] pipeline. +#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub enum VerifySignature +where + T: Config + Send + Sync, +{ + /// The extension will verify the signature and, if successful, authorize a traditionally + /// signed transaction. + Signed { + /// The signature provided by the transaction submitter. + signature: T::Signature, + /// The account that signed the payload. + account: T::AccountId, + }, + /// The extension is disabled and will be passthrough. + Disabled, +} + +impl core::fmt::Debug for VerifySignature +where + T: Config + Send + Sync, +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "VerifySignature") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result { + Ok(()) + } +} + +impl VerifySignature +where + T: Config + Send + Sync, +{ + /// Create a new extension instance that will validate the provided signature. + pub fn new_with_signature(signature: T::Signature, account: T::AccountId) -> Self { + Self::Signed { signature, account } + } + + /// Create a new passthrough extension instance. + pub fn new_disabled() -> Self { + Self::Disabled + } +} + +impl TransactionExtension for VerifySignature +where + T: Config + Send + Sync, + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, +{ + const IDENTIFIER: &'static str = "VerifyMultiSignature"; + type Implicit = (); + type Val = (); + type Pre = (); + + fn weight(&self, _call: &T::RuntimeCall) -> Weight { + match &self { + // The benchmarked weight of the payload construction and signature checking. + Self::Signed { .. } => T::WeightInfo::verify_signature(), + // When the extension is passthrough, it consumes no weight. + Self::Disabled => Weight::zero(), + } + } + + fn validate( + &self, + mut origin: ::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, + _len: usize, + _: (), + inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + // If the extension is disabled, return early. + let (signature, account) = match &self { + Self::Signed { signature, account } => (signature, account), + Self::Disabled => return Ok((Default::default(), (), origin)), + }; + + // This extension must receive an unauthorized origin as it is meant to headline the + // authorization extension pipeline. Any extensions that precede this one must not authorize + // any origin and serve some other functional purpose. + if origin.is_transaction_authorized() { + return Err(InvalidTransaction::BadSigner.into()); + } + + // Construct the payload that the signature will be validated against. The inherited + // implication contains the encoded bytes of the call and all of the extension data of the + // extensions that follow in the `TransactionExtension` pipeline. + // + // In other words: + // - extensions that precede this extension are ignored in terms of signature validation; + // - extensions that follow this extension are included in the payload to be signed (as if + // they were the entire `SignedExtension` pipeline in the traditional signed transaction + // model). + // + // The encoded bytes of the payload are then hashed using `blake2_256`. + let msg = inherited_implication.using_encoded(blake2_256); + + // The extension was enabled, so the signature must match. + if !signature.verify(&msg[..], account) { + Err(InvalidTransaction::BadProof)? + } + + // Return the signer as the transaction origin. + origin.set_caller_from_signed(account.clone()); + Ok((ValidTransaction::default(), (), origin)) + } + + impl_tx_ext_default!(T::RuntimeCall; prepare); +} diff --git a/substrate/frame/verify-signature/src/lib.rs b/substrate/frame/verify-signature/src/lib.rs new file mode 100644 index 000000000000..96d83dbef9f7 --- /dev/null +++ b/substrate/frame/verify-signature/src/lib.rs @@ -0,0 +1,68 @@ +// 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. + +//! Transaction extension which validates a signature against a payload constructed from a call and +//! the rest of the transaction extension pipeline. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod extension; +#[cfg(test)] +mod tests; +pub mod weights; + +extern crate alloc; + +#[cfg(feature = "runtime-benchmarks")] +pub use benchmarking::BenchmarkHelper; +use codec::{Decode, Encode}; +pub use extension::VerifySignature; +use frame_support::Parameter; +pub use weights::WeightInfo; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use sp_runtime::traits::{IdentifyAccount, Verify}; + + #[pallet::pallet] + pub struct Pallet(_); + + /// Configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Signature type that the extension of this pallet can verify. + type Signature: Verify + + Parameter + + Encode + + Decode + + Send + + Sync; + /// The account identifier used by this pallet's signature type. + type AccountIdentifier: IdentifyAccount; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + /// Helper to create a signature to be benchmarked. + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: BenchmarkHelper; + } +} diff --git a/substrate/frame/verify-signature/src/tests.rs b/substrate/frame/verify-signature/src/tests.rs new file mode 100644 index 000000000000..63a310506eec --- /dev/null +++ b/substrate/frame/verify-signature/src/tests.rs @@ -0,0 +1,150 @@ +// 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. + +// Tests for Utility Pallet + +#![cfg(test)] + +use super::*; + +use extension::VerifySignature; +use frame_support::{ + derive_impl, + dispatch::GetDispatchInfo, + 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, +}; + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + VerifySignaturePallet: crate, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct BenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +impl crate::BenchmarkHelper for BenchmarkHelper { + fn create_signature(_entropy: &[u8], msg: &[u8]) -> (TestSignature, u64) { + (TestSignature(0, msg.to_vec()), 0) + } +} + +impl crate::Config for Test { + type Signature = TestSignature; + type AccountIdentifier = UintAuthorityId; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; +} + +#[cfg(feature = "runtime-benchmarks")] +pub fn new_test_ext() -> sp_io::TestExternalities { + use sp_runtime::BuildStorage; + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +#[test] +fn verification_works() { + let who = 0; + let call: RuntimeCall = SystemCall::remark { remark: vec![] }.into(); + 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, 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; + let call: RuntimeCall = SystemCall::remark { remark: vec![] }.into(); + let sig = TestSignature(0, b"bogus message".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_starting_origin() { + let who = 0; + let call: RuntimeCall = SystemCall::remark { remark: vec![] }.into(); + let sig = TestSignature(0, b"bogus message".to_vec()); + let info = call.get_dispatch_info(); + + assert_eq!( + VerifySignature::::new_with_signature(sig, who) + .validate_only(Some(42).into(), &call, &info, 0, TransactionSource::External, 0) + .unwrap_err(), + TransactionValidityError::Invalid(InvalidTransaction::BadSigner) + ); +} + +#[test] +fn disabled_extension_works() { + let who = 42; + let call: RuntimeCall = SystemCall::remark { remark: vec![] }.into(); + let info = call.get_dispatch_info(); + + let (_, _, origin) = VerifySignature::::new_disabled() + .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 new file mode 100644 index 000000000000..a8bfa9ea902d --- /dev/null +++ b/substrate/frame/verify-signature/src/weights.rs @@ -0,0 +1,78 @@ +// 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. + +//! Autogenerated weights for `pallet_verify_signature` +//! +//! 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: `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 +// benchmark +// pallet +// --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 +// --output=./substrate/frame/verify-signature/src/weights.rs +// --header=./substrate/HEADER-APACHE2 +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_verify_signature`. +pub trait WeightInfo { + fn verify_signature() -> Weight; +} + +/// Weights for `pallet_verify_signature` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn verify_signature() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 46_215_000 picoseconds. + Weight::from_parts(46_714_000, 0) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + fn verify_signature() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 46_215_000 picoseconds. + Weight::from_parts(46_714_000, 0) + } +} diff --git a/substrate/frame/vesting/src/benchmarking.rs b/substrate/frame/vesting/src/benchmarking.rs index 68214c4f47cc..3797ee9079db 100644 --- a/substrate/frame/vesting/src/benchmarking.rs +++ b/substrate/frame/vesting/src/benchmarking.rs @@ -19,13 +19,12 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::{v2::*, BenchmarkError}; use frame_support::assert_ok; -use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System, RawOrigin}; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul}; -use super::{Vesting as VestingStorage, *}; -use crate::Pallet as Vesting; +use crate::*; const SEED: u32 = 0; @@ -35,24 +34,23 @@ type BalanceOf = fn add_locks(who: &T::AccountId, n: u8) { for id in 0..n { let lock_id = [id; 8]; - let locked = 256u32; + let locked = 256_u32; let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; T::Currency::set_lock(lock_id, who, locked.into(), reasons); } } fn add_vesting_schedules( - target: AccountIdLookupOf, + target: &T::AccountId, n: u32, ) -> Result, &'static str> { let min_transfer = T::MinVestedTransfer::get(); - let locked = min_transfer.checked_mul(&20u32.into()).unwrap(); + let locked = min_transfer.checked_mul(&20_u32.into()).unwrap(); // Schedule has a duration of 20. let per_block = min_transfer; - let starting_block = 1u32; + let starting_block = 1_u32; - let source: T::AccountId = account("source", 0, SEED); - let source_lookup = T::Lookup::unlookup(source.clone()); + let source = account("source", 0, SEED); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); T::BlockNumberProvider::set_block_number(BlockNumberFor::::zero()); @@ -62,11 +60,7 @@ fn add_vesting_schedules( total_locked += locked; let schedule = VestingInfo::new(locked, per_block, starting_block.into()); - assert_ok!(Vesting::::do_vested_transfer( - source_lookup.clone(), - target.clone(), - schedule - )); + assert_ok!(Pallet::::do_vested_transfer(&source, target, schedule)); // Top up to guarantee we can always transfer another schedule. T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); @@ -75,344 +69,375 @@ fn add_vesting_schedules( Ok(total_locked) } -benchmarks! { - vest_locked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; +#[benchmarks] +mod benchmarks { + use super::*; - let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); + #[benchmark] + fn vest_locked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, T::MAX_VESTING_SCHEDULES>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); - let expected_balance = add_vesting_schedules::(caller_lookup, s)?; + let expected_balance = add_vesting_schedules::(&caller, s)?; // At block zero, everything is vested. - assert_eq!(System::::block_number(), BlockNumberFor::::zero()); + assert_eq!(frame_system::Pallet::::block_number(), BlockNumberFor::::zero()); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting schedule not added", ); - }: vest(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + vest(RawOrigin::Signed(caller.clone())); + // Nothing happened since everything is still vested. assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting schedule was removed", ); - } - vest_unlocked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); + #[benchmark] + fn vest_unlocked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, T::MAX_VESTING_SCHEDULES>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); - add_vesting_schedules::(caller_lookup, s)?; + add_vesting_schedules::(&caller, s)?; // At block 21, everything is unlocked. - T::BlockNumberProvider::set_block_number(21u32.into()); + T::BlockNumberProvider::set_block_number(21_u32.into()); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(BalanceOf::::zero()), "Vesting schedule still active", ); - }: vest(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + vest(RawOrigin::Signed(caller.clone())); + // Vesting schedule is removed! - assert_eq!( - Vesting::::vesting_balance(&caller), - None, - "Vesting schedule was not removed", - ); - } + assert_eq!(Pallet::::vesting_balance(&caller), None, "Vesting schedule was not removed",); - vest_other_locked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let other: T::AccountId = account("other", 0, SEED); + #[benchmark] + fn vest_other_locked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, T::MAX_VESTING_SCHEDULES>, + ) -> Result<(), BenchmarkError> { + let other = account::("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); - let expected_balance = add_vesting_schedules::(other_lookup.clone(), s)?; + let expected_balance = add_vesting_schedules::(&other, s)?; // At block zero, everything is vested. - assert_eq!(System::::block_number(), BlockNumberFor::::zero()); + assert_eq!(frame_system::Pallet::::block_number(), BlockNumberFor::::zero()); assert_eq!( - Vesting::::vesting_balance(&other), + Pallet::::vesting_balance(&other), Some(expected_balance), "Vesting schedule not added", ); - let caller: T::AccountId = whitelisted_caller(); - }: vest_other(RawOrigin::Signed(caller.clone()), other_lookup) - verify { + let caller = whitelisted_caller::(); + + #[extrinsic_call] + vest_other(RawOrigin::Signed(caller.clone()), other_lookup); + // Nothing happened since everything is still vested. assert_eq!( - Vesting::::vesting_balance(&other), + Pallet::::vesting_balance(&other), Some(expected_balance), "Vesting schedule was removed", ); - } - vest_other_unlocked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let other: T::AccountId = account("other", 0, SEED); + #[benchmark] + fn vest_other_unlocked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { + let other = account::("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); - add_vesting_schedules::(other_lookup.clone(), s)?; + add_vesting_schedules::(&other, s)?; // At block 21 everything is unlocked. - T::BlockNumberProvider::set_block_number(21u32.into()); + T::BlockNumberProvider::set_block_number(21_u32.into()); assert_eq!( - Vesting::::vesting_balance(&other), + Pallet::::vesting_balance(&other), Some(BalanceOf::::zero()), "Vesting schedule still active", ); - let caller: T::AccountId = whitelisted_caller(); - }: vest_other(RawOrigin::Signed(caller.clone()), other_lookup) - verify { + let caller = whitelisted_caller::(); + + #[extrinsic_call] + vest_other(RawOrigin::Signed(caller.clone()), other_lookup); + // Vesting schedule is removed. - assert_eq!( - Vesting::::vesting_balance(&other), - None, - "Vesting schedule was not removed", - ); - } + assert_eq!(Pallet::::vesting_balance(&other), None, "Vesting schedule was not removed",); - vested_transfer { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; + Ok(()) + } - let caller: T::AccountId = whitelisted_caller(); + #[benchmark] + fn vested_transfer( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<0, { T::MAX_VESTING_SCHEDULES - 1 }>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let target: T::AccountId = account("target", 0, SEED); + let target = account::("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - // Give target existing locks + // Give target existing locks. T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); // Add one vesting schedules. let orig_balance = T::Currency::free_balance(&target); - let mut expected_balance = add_vesting_schedules::(target_lookup.clone(), s)?; + let mut expected_balance = add_vesting_schedules::(&target, s)?; let transfer_amount = T::MinVestedTransfer::get(); - let per_block = transfer_amount.checked_div(&20u32.into()).unwrap(); + let per_block = transfer_amount.checked_div(&20_u32.into()).unwrap(); expected_balance += transfer_amount; - let vesting_schedule = VestingInfo::new( - transfer_amount, - per_block, - 1u32.into(), - ); - }: _(RawOrigin::Signed(caller), target_lookup, vesting_schedule) - verify { + let vesting_schedule = VestingInfo::new(transfer_amount, per_block, 1_u32.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), target_lookup, vesting_schedule); + assert_eq!( orig_balance + expected_balance, T::Currency::free_balance(&target), "Transfer didn't happen", ); assert_eq!( - Vesting::::vesting_balance(&target), + Pallet::::vesting_balance(&target), Some(expected_balance), "Lock not correctly updated", ); - } - force_vested_transfer { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; + Ok(()) + } - let source: T::AccountId = account("source", 0, SEED); + #[benchmark] + fn force_vested_transfer( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<0, { T::MAX_VESTING_SCHEDULES - 1 }>, + ) -> Result<(), BenchmarkError> { + let source = account::("source", 0, SEED); let source_lookup = T::Lookup::unlookup(source.clone()); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); - let target: T::AccountId = account("target", 0, SEED); + let target = account::("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - // Give target existing locks + // Give target existing locks. T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); - // Add one less than max vesting schedules + // Add one less than max vesting schedules. let orig_balance = T::Currency::free_balance(&target); - let mut expected_balance = add_vesting_schedules::(target_lookup.clone(), s)?; + let mut expected_balance = add_vesting_schedules::(&target, s)?; let transfer_amount = T::MinVestedTransfer::get(); - let per_block = transfer_amount.checked_div(&20u32.into()).unwrap(); + let per_block = transfer_amount.checked_div(&20_u32.into()).unwrap(); expected_balance += transfer_amount; - let vesting_schedule = VestingInfo::new( - transfer_amount, - per_block, - 1u32.into(), - ); - }: _(RawOrigin::Root, source_lookup, target_lookup, vesting_schedule) - verify { + let vesting_schedule = VestingInfo::new(transfer_amount, per_block, 1_u32.into()); + + #[extrinsic_call] + _(RawOrigin::Root, source_lookup, target_lookup, vesting_schedule); + assert_eq!( orig_balance + expected_balance, T::Currency::free_balance(&target), "Transfer didn't happen", ); assert_eq!( - Vesting::::vesting_balance(&target), + Pallet::::vesting_balance(&target), Some(expected_balance), - "Lock not correctly updated", - ); - } + "Lock not correctly updated", + ); - not_unlocking_merge_schedules { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 2 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let caller: T::AccountId = account("caller", 0, SEED); - let caller_lookup = T::Lookup::unlookup(caller.clone()); + #[benchmark] + fn not_unlocking_merge_schedules( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<2, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller::(); // Give target existing locks. T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. - let expected_balance = add_vesting_schedules::(caller_lookup, s)?; + let expected_balance = add_vesting_schedules::(&caller, s)?; // Schedules are not vesting at block 0. - assert_eq!(System::::block_number(), BlockNumberFor::::zero()); + assert_eq!(frame_system::Pallet::::block_number(), BlockNumberFor::::zero()); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should equal sum locked of all schedules", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), s as usize, "There should be exactly max vesting schedules" ); - }: merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1) - verify { + + #[extrinsic_call] + merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1); + let expected_schedule = VestingInfo::new( - T::MinVestedTransfer::get() * 20u32.into() * 2u32.into(), - T::MinVestedTransfer::get() * 2u32.into(), - 1u32.into(), + T::MinVestedTransfer::get() * 20_u32.into() * 2_u32.into(), + T::MinVestedTransfer::get() * 2_u32.into(), + 1_u32.into(), ); let expected_index = (s - 2) as usize; + assert_eq!(Vesting::::get(&caller).unwrap()[expected_index], expected_schedule); assert_eq!( - VestingStorage::::get(&caller).unwrap()[expected_index], - expected_schedule - ); - assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should equal total locked of all schedules", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), (s - 1) as usize, "Schedule count should reduce by 1" ); - } - unlocking_merge_schedules { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 2 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } + #[benchmark] + fn unlocking_merge_schedules( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<2, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { // Destination used just for currency transfers in asserts. let test_dest: T::AccountId = account("test_dest", 0, SEED); - let caller: T::AccountId = account("caller", 0, SEED); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - // Give target other locks. + let caller = whitelisted_caller::(); + // Give target existing locks. T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. - let total_transferred = add_vesting_schedules::(caller_lookup, s)?; - - // Go to about half way through all the schedules duration. (They all start at 1, and have a duration of 20 or 21). - T::BlockNumberProvider::set_block_number(11u32.into()); - // We expect half the original locked balance (+ any remainder that vests on the last block). - let expected_balance = total_transferred / 2u32.into(); + let total_transferred = add_vesting_schedules::(&caller, s)?; + + // Go to about half way through all the schedules duration. (They all start at 1, and have a + // duration of 20 or 21). + T::BlockNumberProvider::set_block_number(11_u32.into()); + // We expect half the original locked balance (+ any remainder that vests on the last + // block). + let expected_balance = total_transferred / 2_u32.into(); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should reflect that we are half way through all schedules duration", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), s as usize, "There should be exactly max vesting schedules" ); // The balance is not actually transferable because it has not been unlocked. - assert!(T::Currency::transfer(&caller, &test_dest, expected_balance, ExistenceRequirement::AllowDeath).is_err()); - }: merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1) - verify { + assert!(T::Currency::transfer( + &caller, + &test_dest, + expected_balance, + ExistenceRequirement::AllowDeath + ) + .is_err()); + + #[extrinsic_call] + merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1); + let expected_schedule = VestingInfo::new( - T::MinVestedTransfer::get() * 2u32.into() * 10u32.into(), - T::MinVestedTransfer::get() * 2u32.into(), - 11u32.into(), + T::MinVestedTransfer::get() * 2_u32.into() * 10_u32.into(), + T::MinVestedTransfer::get() * 2_u32.into(), + 11_u32.into(), ); let expected_index = (s - 2) as usize; assert_eq!( - VestingStorage::::get(&caller).unwrap()[expected_index], + Vesting::::get(&caller).unwrap()[expected_index], expected_schedule, "New schedule is properly created and placed" ); assert_eq!( - VestingStorage::::get(&caller).unwrap()[expected_index], - expected_schedule - ); - assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should equal half total locked of all schedules", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), (s - 1) as usize, "Schedule count should reduce by 1" ); // Since merge unlocks all schedules we can now transfer the balance. - assert_ok!( - T::Currency::transfer(&caller, &test_dest, expected_balance, ExistenceRequirement::AllowDeath) - ); - } + assert_ok!(T::Currency::transfer( + &caller, + &test_dest, + expected_balance, + ExistenceRequirement::AllowDeath + )); -force_remove_vesting_schedule { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 2 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let source: T::AccountId = account("source", 0, SEED); - let source_lookup: ::Source = T::Lookup::unlookup(source.clone()); + #[benchmark] + fn force_remove_vesting_schedule( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<2, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { + let source = account::("source", 0, SEED); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); - let target: T::AccountId = account("target", 0, SEED); - let target_lookup: ::Source = T::Lookup::unlookup(target.clone()); + let target = account::("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); // Give target existing locks. add_locks::(&target, l as u8); - let _ = add_vesting_schedules::(target_lookup.clone(), s)?; + add_vesting_schedules::(&target, s)?; // The last vesting schedule. let schedule_index = s - 1; - }: _(RawOrigin::Root, target_lookup, schedule_index) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, target_lookup, schedule_index); + assert_eq!( - VestingStorage::::get(&target).unwrap().len(), + Vesting::::get(&target).unwrap().len(), schedule_index as usize, "Schedule count should reduce by 1" ); + + Ok(()) } - impl_benchmark_test_suite!( - Vesting, - crate::mock::ExtBuilder::default().existential_deposit(256).build(), - crate::mock::Test, - ); + impl_benchmark_test_suite! { + Pallet, + mock::ExtBuilder::default().existential_deposit(256).build(), + mock::Test + } } diff --git a/substrate/frame/vesting/src/lib.rs b/substrate/frame/vesting/src/lib.rs index bfc10efeed79..15f8d397f81c 100644 --- a/substrate/frame/vesting/src/lib.rs +++ b/substrate/frame/vesting/src/lib.rs @@ -66,8 +66,8 @@ use frame_support::{ ensure, storage::bounded_vec::BoundedVec, traits::{ - Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestingSchedule, - WithdrawReasons, + Currency, ExistenceRequirement, Get, LockIdentifier, LockableCurrency, VestedTransfer, + VestingSchedule, WithdrawReasons, }, weights::Weight, }; @@ -351,8 +351,8 @@ pub mod pallet { schedule: VestingInfo, BlockNumberFor>, ) -> DispatchResult { let transactor = ensure_signed(origin)?; - let transactor = ::unlookup(transactor); - Self::do_vested_transfer(transactor, target, schedule) + let target = T::Lookup::lookup(target)?; + Self::do_vested_transfer(&transactor, &target, schedule) } /// Force a vested transfer. @@ -380,7 +380,9 @@ pub mod pallet { schedule: VestingInfo, BlockNumberFor>, ) -> DispatchResult { ensure_root(origin)?; - Self::do_vested_transfer(source, target, schedule) + let target = T::Lookup::lookup(target)?; + let source = T::Lookup::lookup(source)?; + Self::do_vested_transfer(&source, &target, schedule) } /// Merge two vesting schedules together, creating a new vesting schedule that unlocks over @@ -525,8 +527,8 @@ impl Pallet { // Execute a vested transfer from `source` to `target` with the given `schedule`. fn do_vested_transfer( - source: AccountIdLookupOf, - target: AccountIdLookupOf, + source: &T::AccountId, + target: &T::AccountId, schedule: VestingInfo, BlockNumberFor>, ) -> DispatchResult { // Validate user inputs. @@ -534,27 +536,22 @@ impl Pallet { if !schedule.is_valid() { return Err(Error::::InvalidScheduleParams.into()) }; - let target = T::Lookup::lookup(target)?; - let source = T::Lookup::lookup(source)?; // Check we can add to this account prior to any storage writes. Self::can_add_vesting_schedule( - &target, + target, schedule.locked(), schedule.per_block(), schedule.starting_block(), )?; - T::Currency::transfer( - &source, - &target, - schedule.locked(), - ExistenceRequirement::AllowDeath, - )?; + T::Currency::transfer(source, target, schedule.locked(), ExistenceRequirement::AllowDeath)?; // We can't let this fail because the currency transfer has already happened. + // Must be successful as it has been checked before. + // Better to return error on failure anyway. let res = Self::add_vesting_schedule( - &target, + target, schedule.locked(), schedule.per_block(), schedule.starting_block(), @@ -751,8 +748,8 @@ where Ok(()) } - // Ensure we can call `add_vesting_schedule` without error. This should always - // be called prior to `add_vesting_schedule`. + /// Ensure we can call `add_vesting_schedule` without error. This should always + /// be called prior to `add_vesting_schedule`. fn can_add_vesting_schedule( who: &T::AccountId, locked: BalanceOf, @@ -784,3 +781,32 @@ where Ok(()) } } + +/// An implementation that allows the Vesting Pallet to handle a vested transfer +/// on behalf of another Pallet. +impl VestedTransfer for Pallet +where + BalanceOf: MaybeSerializeDeserialize + Debug, +{ + type Currency = T::Currency; + type Moment = BlockNumberFor; + + fn vested_transfer( + source: &T::AccountId, + target: &T::AccountId, + locked: BalanceOf, + per_block: BalanceOf, + starting_block: BlockNumberFor, + ) -> DispatchResult { + use frame_support::storage::{with_transaction, TransactionOutcome}; + let schedule = VestingInfo::new(locked, per_block, starting_block); + with_transaction(|| -> TransactionOutcome { + let result = Self::do_vested_transfer(source, target, schedule); + + match &result { + Ok(()) => TransactionOutcome::Commit(result), + _ => TransactionOutcome::Rollback(result), + } + }) + } +} diff --git a/substrate/frame/vesting/src/tests.rs b/substrate/frame/vesting/src/tests.rs index 57cb59f27a4d..0dd7133d930a 100644 --- a/substrate/frame/vesting/src/tests.rs +++ b/substrate/frame/vesting/src/tests.rs @@ -280,13 +280,14 @@ fn extra_balance_should_transfer() { // Account 1 has only 5 units vested at block 1 (plus 150 unvested) assert_eq!(Vesting::vesting_balance(&1), Some(45)); assert_ok!(Vesting::vest(Some(1).into())); - assert_ok!(Balances::transfer_allow_death(Some(1).into(), 3, 155)); // Account 1 can send extra units gained + // Account 1 can send extra units gained + assert_ok!(Balances::transfer_allow_death(Some(1).into(), 3, 155)); // Account 2 has no units vested at block 1, but gained 100 assert_eq!(Vesting::vesting_balance(&2), Some(200)); assert_ok!(Vesting::vest(Some(2).into())); - assert_ok!(Balances::transfer_allow_death(Some(2).into(), 3, 100)); // Account 2 can send extra - // units gained + // Account 2 can send extra units gained + assert_ok!(Balances::transfer_allow_death(Some(2).into(), 3, 100)); }); } @@ -295,14 +296,16 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { ExtBuilder::default().existential_deposit(256).build().execute_with(|| { let user12_free_balance = Balances::free_balance(&12); - assert_eq!(user12_free_balance, 2560); // Account 12 has free balance - // Account 12 has liquid funds + // Account 12 has free balance + assert_eq!(user12_free_balance, 2560); + // Account 12 has liquid funds assert_eq!(Vesting::vesting_balance(&12), Some(user12_free_balance - 256 * 5)); // Account 12 has delayed vesting let user12_vesting_schedule = VestingInfo::new( 256 * 5, - 64, // Vesting over 20 blocks + // Vesting over 20 blocks + 64, 10, ); assert_eq!(VestingStorage::::get(&12).unwrap(), vec![user12_vesting_schedule]); @@ -630,8 +633,10 @@ fn merge_ongoing_schedules() { let sched1 = VestingInfo::new( ED * 10, - ED, // Vest over 10 blocks. - sched0.starting_block() + 5, // Start at block 15. + // Vest over 10 blocks. + ED, + // Start at block 15. + sched0.starting_block() + 5, ); assert_ok!(Vesting::vested_transfer(Some(4).into(), 2, sched1)); assert_eq!(VestingStorage::::get(&2).unwrap(), vec![sched0, sched1]); @@ -1191,3 +1196,43 @@ fn remove_vesting_schedule() { ); }); } + +#[test] +fn vested_transfer_impl_works() { + ExtBuilder::default().existential_deposit(ED).build().execute_with(|| { + assert_eq!(Balances::free_balance(&3), 256 * 30); + assert_eq!(Balances::free_balance(&4), 256 * 40); + // Account 4 should not have any vesting yet. + assert_eq!(VestingStorage::::get(&4), None); + + // Basic working scenario + assert_ok!(>::vested_transfer( + &3, + &4, + ED * 5, + ED * 5 / 20, + 10 + )); + // Now account 4 should have vesting. + let new_vesting_schedule = VestingInfo::new( + ED * 5, + (ED * 5) / 20, // Vesting over 20 blocks + 10, + ); + assert_eq!(VestingStorage::::get(&4).unwrap(), vec![new_vesting_schedule]); + // Account 4 has 5 * 256 locked. + assert_eq!(Vesting::vesting_balance(&4), Some(256 * 5)); + + // If the transfer fails (because they don't have enough balance), no storage is changed. + assert_noop!( + >::vested_transfer(&3, &4, ED * 9999, ED * 5 / 20, 10), + TokenError::FundsUnavailable + ); + + // If applying the vesting schedule fails (per block is 0), no storage is changed. + assert_noop!( + >::vested_transfer(&3, &4, ED * 5, 0, 10), + Error::::InvalidScheduleParams + ); + }); +} 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/src/benchmarking.rs b/substrate/frame/whitelist/src/benchmarking.rs index cbe6ee4becd0..0d7605d9752b 100644 --- a/substrate/frame/whitelist/src/benchmarking.rs +++ b/substrate/frame/whitelist/src/benchmarking.rs @@ -75,7 +75,7 @@ mod benchmarks { .map_err(|_| BenchmarkError::Weightless)?; let remark = alloc::vec![1u8; n as usize]; let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let encoded_call = call.encode(); let call_encoded_len = encoded_call.len() as u32; let call_hash = T::Hashing::hash_of(&call); diff --git a/substrate/frame/whitelist/src/lib.rs b/substrate/frame/whitelist/src/lib.rs index de16c2c2da88..28887e0ca4ac 100644 --- a/substrate/frame/whitelist/src/lib.rs +++ b/substrate/frame/whitelist/src/lib.rs @@ -178,7 +178,7 @@ pub mod pallet { .map_err(|_| Error::::UndecodableCall)?; ensure!( - call.get_dispatch_info().weight.all_lte(call_weight_witness), + call.get_dispatch_info().call_weight.all_lte(call_weight_witness), Error::::InvalidCallWeightWitness ); @@ -191,7 +191,7 @@ pub mod pallet { #[pallet::call_index(3)] #[pallet::weight({ - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let call_len = call.encoded_size() as u32; T::WeightInfo::dispatch_whitelisted_call_with_preimage(call_len) diff --git a/substrate/frame/whitelist/src/tests.rs b/substrate/frame/whitelist/src/tests.rs index 3a60adbcfbed..b53cc93b1953 100644 --- a/substrate/frame/whitelist/src/tests.rs +++ b/substrate/frame/whitelist/src/tests.rs @@ -73,7 +73,7 @@ fn test_whitelist_call_and_remove() { fn test_whitelist_call_and_execute() { new_test_ext().execute_with(|| { let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let encoded_call = call.encode(); let call_encoded_len = encoded_call.len() as u32; let call_hash = ::Hashing::hash(&encoded_call[..]); @@ -153,7 +153,7 @@ fn test_whitelist_call_and_execute_failing_call() { call_encoded_len: Default::default(), call_weight_witness: Weight::zero(), }); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let encoded_call = call.encode(); let call_encoded_len = encoded_call.len() as u32; let call_hash = ::Hashing::hash(&encoded_call[..]); @@ -200,7 +200,7 @@ fn test_whitelist_call_and_execute_without_note_preimage() { fn test_whitelist_call_and_execute_decode_consumes_all() { new_test_ext().execute_with(|| { let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); - let call_weight = call.get_dispatch_info().weight; + let call_weight = call.get_dispatch_info().call_weight; let mut call = call.encode(); // Appending something does not make the encoded call invalid. // This tests that the decode function consumes all data. 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/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 659307e7b0f8..191578f432ad 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -20,7 +20,7 @@ proc-macro = true [dependencies] quote = { workspace = true } -syn = { features = ["extra-traits", "fold", "full", "visit"], workspace = true } +syn = { features = ["extra-traits", "fold", "full", "visit", "visit-mut"], workspace = true } proc-macro2 = { workspace = true } blake2 = { workspace = true } proc-macro-crate = { 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..6be396339259 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 { +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/tests/decl_and_impl.rs b/substrate/primitives/api/test/tests/decl_and_impl.rs index 211a08561fd4..890cf6eccdbc 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,62 @@ 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() { + 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/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/pow/Cargo.toml b/substrate/primitives/consensus/pow/Cargo.toml index 8731015f7da2..171137a1a04e 100644 --- a/substrate/primitives/consensus/pow/Cargo.toml +++ b/substrate/primitives/consensus/pow/Cargo.toml @@ -23,9 +23,4 @@ sp-runtime = { workspace = true } [features] default = ["std"] -std = [ - "codec/std", - "sp-api/std", - "sp-core/std", - "sp-runtime/std", -] +std = ["codec/std", "sp-api/std", "sp-core/std", "sp-runtime/std"] diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index 43f8c5514f7f..2f993d3167a1 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -23,12 +23,7 @@ sp-timestamp = { workspace = true } [features] default = ["std"] -std = [ - "codec/std", - "scale-info/std", - "serde/std", - "sp-timestamp/std", -] +std = ["codec/std", "scale-info/std", "serde/std", "sp-timestamp/std"] # Serde support without relying on std features. serde = ["dep:serde", "scale-info/serde"] diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index fd7fe7767204..cf24861e233c 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -17,10 +17,10 @@ //! 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::{format, string::String, vec}; -use alloc::{str, vec::Vec}; +use alloc::{string::String, vec}; use bip39::{Language, Mnemonic}; use codec::{Decode, Encode, MaxEncodedLen}; use core::hash::Hash; @@ -419,6 +419,17 @@ pub fn set_default_ss58_version(new_default: Ss58AddressFormat) { DEFAULT_VERSION.store(new_default.into(), core::sync::atomic::Ordering::Relaxed); } +/// Interprets the string `s` in order to generate a public key without password. +/// +/// Function will panic when invalid string is provided. +pub fn get_public_from_string_or_panic( + s: &str, +) -> ::Public { + TPublic::Pair::from_string(&format!("//{}", s), None) + .expect("Function expects valid argument; qed") + .public() +} + #[cfg(feature = "std")] impl + AsRef<[u8]> + Public + Derive> Ss58Codec for T { fn from_string(s: &str) -> Result { @@ -1180,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/genesis-builder/src/lib.rs b/substrate/primitives/genesis-builder/src/lib.rs index 07317bc4cb52..9abc27868864 100644 --- a/substrate/primitives/genesis-builder/src/lib.rs +++ b/substrate/primitives/genesis-builder/src/lib.rs @@ -17,17 +17,33 @@ #![cfg_attr(not(feature = "std"), no_std)] -//! Substrate genesis config builder +//! # Substrate genesis config builder. //! -//! For FRAME based runtimes, this runtime interface provides means to interact with -//! `RuntimeGenesisConfig`. Runtime provides a default `RuntimeGenesisConfig` structure in a form of -//! the JSON blob. +//! This crate contains [`GenesisBuilder`], a runtime-api to be implemented by runtimes, in order to +//! express their genesis state. //! -//! For non-FRAME runtimes this interface is intended to build genesis state of the runtime basing -//! on some input arbitrary bytes array. This documentation uses term `RuntimeGenesisConfig`, which -//! for non-FRAME runtimes may be understood as the runtime-side entity representing initial runtime -//! configuration. The representation of the preset is an arbitrary `Vec` and does not -//! necessarily have to represent a JSON blob. +//! The overall flow of the methods in [`GenesisBuilder`] is as follows: +//! +//! 1. [`GenesisBuilder::preset_names`]: A runtime exposes a number of different +//! `RuntimeGenesisConfig` variations, each of which is called a `preset`, and is identified by a +//! [`PresetId`]. All runtimes are encouraged to expose at least [`DEV_RUNTIME_PRESET`] and +//! [`LOCAL_TESTNET_RUNTIME_PRESET`] presets for consistency. +//! 2. [`GenesisBuilder::get_preset`]: Given a `PresetId`, this the runtime returns the JSON blob +//! representation of the `RuntimeGenesisConfig` for that preset. This JSON blob is often mixed +//! into the broader `chain_spec`. If `None` is given, [`GenesisBuilder::get_preset`] provides a +//! JSON represention of the default `RuntimeGenesisConfig` (by simply serializing the +//! `RuntimeGenesisConfig::default()` value into JSON format). This is used as a base for +//! applying patches / presets. + +//! 3. [`GenesisBuilder::build_state`]: Given a JSON blob, this method should deserialize it and +//! enact it (using `frame_support::traits::BuildGenesisConfig` for Frame-based runtime), +//! essentially writing it to the state. +//! +//! The first two flows are often done in between a runtime, and the `chain_spec_builder` binary. +//! The latter is used when a new blockchain is launched to enact and store the genesis state. See +//! the documentation of `chain_spec_builder` for more info. +//! +//! ## Patching //! //! The runtime may provide a number of partial predefined `RuntimeGenesisConfig` configurations in //! the form of patches which shall be applied on top of the default `RuntimeGenesisConfig`. The @@ -35,32 +51,35 @@ //! customized in the default runtime genesis config. These predefined configurations are referred //! to as presets. //! -//! This allows the runtime to provide a number of predefined configs (e.g. for different -//! testnets or development) without neccessity to leak the runtime types outside the itself (e.g. -//! node or chain-spec related tools). +//! This allows the runtime to provide a number of predefined configs (e.g. for different testnets +//! or development) without necessarily to leak the runtime types outside itself (e.g. node or +//! chain-spec related tools). +//! +//! ## FRAME vs. non-FRAME +//! +//! For FRAME based runtimes [`GenesisBuilder`] provides means to interact with +//! `RuntimeGenesisConfig`. +//! +//! For non-FRAME runtimes this interface is intended to build genesis state of the runtime basing +//! on some input arbitrary bytes array. This documentation uses term `RuntimeGenesisConfig`, which +//! for non-FRAME runtimes may be understood as the "runtime-side entity representing initial +//! runtime genesis configuration". The representation of the preset is an arbitrary `Vec` and +//! does not necessarily have to represent a JSON blob. //! -//! This Runtime API allows to interact with `RuntimeGenesisConfig`, in particular: -//! - provide the list of available preset names, -//! - provide a number of named presets of `RuntimeGenesisConfig`, -//! - provide a JSON represention of the default `RuntimeGenesisConfig` (by simply serializing the -//! default `RuntimeGenesisConfig` struct into JSON format), -//! - deserialize the full `RuntimeGenesisConfig` from given JSON blob and put the resulting -//! `RuntimeGenesisConfig` structure into the state storage creating the initial runtime's state. -//! Allows to build customized genesis. This operation internally calls `GenesisBuild::build` -//! function for all runtime pallets. +//! ## Genesis Block State //! //! Providing externalities with an empty storage and putting `RuntimeGenesisConfig` into storage //! (by calling `build_state`) allows to construct the raw storage of `RuntimeGenesisConfig` //! 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. @@ -75,14 +94,15 @@ pub const DEV_RUNTIME_PRESET: &'static str = "development"; pub const LOCAL_TESTNET_RUNTIME_PRESET: &'static str = "local_testnet"; sp_api::decl_runtime_apis! { - /// API to interact with RuntimeGenesisConfig for the runtime + /// API to interact with `RuntimeGenesisConfig` for the runtime pub trait GenesisBuilder { /// Build `RuntimeGenesisConfig` from a JSON blob not using any defaults and store it in the /// storage. /// - /// In the case of a FRAME-based runtime, this function deserializes the full `RuntimeGenesisConfig` from the given JSON blob and - /// puts it into the storage. If the provided JSON blob is incorrect or incomplete or the - /// deserialization fails, an error is returned. + /// In the case of a FRAME-based runtime, this function deserializes the full + /// `RuntimeGenesisConfig` from the given JSON blob and puts it into the storage. If the + /// provided JSON blob is incorrect or incomplete or the deserialization fails, an error + /// is returned. /// /// Please note that provided JSON blob must contain all `RuntimeGenesisConfig` fields, no /// defaults will be used. @@ -91,7 +111,7 @@ sp_api::decl_runtime_apis! { /// Returns a JSON blob representation of the built-in `RuntimeGenesisConfig` identified by /// `id`. /// - /// If `id` is `None` the function returns JSON blob representation of the default + /// If `id` is `None` the function should return JSON blob representation of the default /// `RuntimeGenesisConfig` struct of the runtime. Implementation must provide default /// `RuntimeGenesisConfig`. /// diff --git a/substrate/primitives/inherents/src/lib.rs b/substrate/primitives/inherents/src/lib.rs index 80787669856f..0ddc12dde061 100644 --- a/substrate/primitives/inherents/src/lib.rs +++ b/substrate/primitives/inherents/src/lib.rs @@ -98,10 +98,10 @@ //! and production. //! //! ``` -//! # use sp_runtime::testing::ExtrinsicWrapper; +//! # use sp_runtime::testing::{MockCallU64, TestXt}; //! # use sp_inherents::{InherentIdentifier, InherentData}; //! # use futures::FutureExt; -//! # type Block = sp_runtime::testing::Block>; +//! # type Block = sp_runtime::testing::Block>; //! # const INHERENT_IDENTIFIER: InherentIdentifier = *b"testinh0"; //! # struct InherentDataProvider; //! # #[async_trait::async_trait] diff --git a/substrate/primitives/keyring/src/bandersnatch.rs b/substrate/primitives/keyring/src/bandersnatch.rs index 67fc5c47df64..64d3c314124d 100644 --- a/substrate/primitives/keyring/src/bandersnatch.rs +++ b/substrate/primitives/keyring/src/bandersnatch.rs @@ -18,6 +18,8 @@ //! A set of well-known keys used for testing. pub use sp_core::bandersnatch; + +use crate::ParseKeyringError; #[cfg(feature = "std")] use sp_core::bandersnatch::Signature; use sp_core::{ @@ -27,7 +29,7 @@ use sp_core::{ }; extern crate alloc; -use alloc::{fmt, format, str::FromStr, string::String, vec::Vec}; +use alloc::{format, str::FromStr, string::String, vec::Vec}; /// Set of test accounts. #[derive( @@ -107,15 +109,6 @@ impl From for &'static str { } } -#[derive(Debug)] -pub struct ParseKeyringError; - -impl fmt::Display for ParseKeyringError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ParseKeyringError") - } -} - impl FromStr for Keyring { type Err = ParseKeyringError; diff --git a/substrate/primitives/keyring/src/ed25519.rs b/substrate/primitives/keyring/src/ed25519.rs index 98ca368e53ca..235b5d5c9931 100644 --- a/substrate/primitives/keyring/src/ed25519.rs +++ b/substrate/primitives/keyring/src/ed25519.rs @@ -18,6 +18,8 @@ //! Support code for the runtime. A set of test accounts. pub use sp_core::ed25519; + +use crate::ParseKeyringError; #[cfg(feature = "std")] use sp_core::ed25519::Signature; use sp_core::{ @@ -27,7 +29,7 @@ use sp_core::{ use sp_runtime::AccountId32; extern crate alloc; -use alloc::{format, string::String, vec::Vec}; +use alloc::{format, str::FromStr, string::String, vec::Vec}; /// Set of test accounts. #[derive( @@ -105,6 +107,14 @@ impl Keyring { pub fn to_seed(self) -> String { format!("//{}", self) } + + pub fn well_known() -> impl Iterator { + Self::iter().take(12) + } + + pub fn invulnerable() -> impl Iterator { + Self::iter().take(6) + } } impl From for &'static str { @@ -134,6 +144,30 @@ impl From for sp_runtime::MultiSigner { } } +impl FromStr for Keyring { + type Err = ParseKeyringError; + + fn from_str(s: &str) -> Result::Err> { + match s { + "Alice" | "alice" => Ok(Keyring::Alice), + "Bob" | "bob" => Ok(Keyring::Bob), + "Charlie" | "charlie" => Ok(Keyring::Charlie), + "Dave" | "dave" => Ok(Keyring::Dave), + "Eve" | "eve" => Ok(Keyring::Eve), + "Ferdie" | "ferdie" => Ok(Keyring::Ferdie), + "Alice//stash" | "alice//stash" => Ok(Keyring::AliceStash), + "Bob//stash" | "bob//stash" => Ok(Keyring::BobStash), + "Charlie//stash" | "charlie//stash" => Ok(Keyring::CharlieStash), + "Dave//stash" | "dave//stash" => Ok(Keyring::DaveStash), + "Eve//stash" | "eve//stash" => Ok(Keyring::EveStash), + "Ferdie//stash" | "ferdie//stash" => Ok(Keyring::FerdieStash), + "One" | "one" => Ok(Keyring::One), + "Two" | "two" => Ok(Keyring::Two), + _ => Err(ParseKeyringError), + } + } +} + impl From for Public { fn from(k: Keyring) -> Self { Public::from_raw(k.into()) @@ -221,4 +255,40 @@ mod tests { fn verify_static_public_keys() { assert!(Keyring::iter().all(|k| { k.pair().public().as_ref() == <[u8; 32]>::from(k) })); } + + #[test] + fn verify_well_known() { + assert_eq!( + Keyring::well_known().collect::>(), + vec![ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie, + Keyring::AliceStash, + Keyring::BobStash, + Keyring::CharlieStash, + Keyring::DaveStash, + Keyring::EveStash, + Keyring::FerdieStash + ] + ); + } + + #[test] + fn verify_invulnerable() { + assert_eq!( + Keyring::invulnerable().collect::>(), + vec![ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie + ] + ); + } } diff --git a/substrate/primitives/keyring/src/lib.rs b/substrate/primitives/keyring/src/lib.rs index f753bf4b0dd6..008c01b150f0 100644 --- a/substrate/primitives/keyring/src/lib.rs +++ b/substrate/primitives/keyring/src/lib.rs @@ -19,6 +19,9 @@ #![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; +use alloc::fmt; + /// Test account crypto for sr25519. pub mod sr25519; @@ -42,3 +45,13 @@ 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; + +impl fmt::Display for ParseKeyringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ParseKeyringError") + } +} diff --git a/substrate/primitives/keyring/src/sr25519.rs b/substrate/primitives/keyring/src/sr25519.rs index a3a506152d7d..5ff9056566bc 100644 --- a/substrate/primitives/keyring/src/sr25519.rs +++ b/substrate/primitives/keyring/src/sr25519.rs @@ -18,6 +18,8 @@ //! Support code for the runtime. A set of test accounts. pub use sp_core::sr25519; + +use crate::ParseKeyringError; #[cfg(feature = "std")] use sp_core::sr25519::Signature; use sp_core::{ @@ -28,7 +30,7 @@ use sp_core::{ use sp_runtime::AccountId32; extern crate alloc; -use alloc::{fmt, format, str::FromStr, string::String, vec::Vec}; +use alloc::{format, str::FromStr, string::String, vec::Vec}; /// Set of test accounts. #[derive( @@ -116,6 +118,14 @@ impl Keyring { pub fn numeric_id(idx: usize) -> AccountId32 { (*Self::numeric(idx).public().as_array_ref()).into() } + + pub fn well_known() -> impl Iterator { + Self::iter().take(12) + } + + pub fn invulnerable() -> impl Iterator { + Self::iter().take(6) + } } impl From for &'static str { @@ -145,28 +155,25 @@ impl From for sp_runtime::MultiSigner { } } -#[derive(Debug)] -pub struct ParseKeyringError; - -impl fmt::Display for ParseKeyringError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ParseKeyringError") - } -} - impl FromStr for Keyring { type Err = ParseKeyringError; fn from_str(s: &str) -> Result::Err> { match s { - "alice" => Ok(Keyring::Alice), - "bob" => Ok(Keyring::Bob), - "charlie" => Ok(Keyring::Charlie), - "dave" => Ok(Keyring::Dave), - "eve" => Ok(Keyring::Eve), - "ferdie" => Ok(Keyring::Ferdie), - "one" => Ok(Keyring::One), - "two" => Ok(Keyring::Two), + "Alice" | "alice" => Ok(Keyring::Alice), + "Bob" | "bob" => Ok(Keyring::Bob), + "Charlie" | "charlie" => Ok(Keyring::Charlie), + "Dave" | "dave" => Ok(Keyring::Dave), + "Eve" | "eve" => Ok(Keyring::Eve), + "Ferdie" | "ferdie" => Ok(Keyring::Ferdie), + "Alice//stash" | "alice//stash" => Ok(Keyring::AliceStash), + "Bob//stash" | "bob//stash" => Ok(Keyring::BobStash), + "Charlie//stash" | "charlie//stash" => Ok(Keyring::CharlieStash), + "Dave//stash" | "dave//stash" => Ok(Keyring::DaveStash), + "Eve//stash" | "eve//stash" => Ok(Keyring::EveStash), + "Ferdie//stash" | "ferdie//stash" => Ok(Keyring::FerdieStash), + "One" | "one" => Ok(Keyring::One), + "Two" | "two" => Ok(Keyring::Two), _ => Err(ParseKeyringError), } } @@ -254,8 +261,45 @@ mod tests { &Keyring::Bob.public(), )); } + #[test] fn verify_static_public_keys() { assert!(Keyring::iter().all(|k| { k.pair().public().as_ref() == <[u8; 32]>::from(k) })); } + + #[test] + fn verify_well_known() { + assert_eq!( + Keyring::well_known().collect::>(), + vec![ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie, + Keyring::AliceStash, + Keyring::BobStash, + Keyring::CharlieStash, + Keyring::DaveStash, + Keyring::EveStash, + Keyring::FerdieStash + ] + ); + } + + #[test] + fn verify_invulnerable() { + assert_eq!( + Keyring::invulnerable().collect::>(), + vec![ + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave, + Keyring::Eve, + Keyring::Ferdie + ] + ); + } } diff --git a/substrate/primitives/metadata-ir/src/lib.rs b/substrate/primitives/metadata-ir/src/lib.rs index 18b20f2ccaac..4bd13b935afd 100644 --- a/substrate/primitives/metadata-ir/src/lib.rs +++ b/substrate/primitives/metadata-ir/src/lib.rs @@ -86,7 +86,7 @@ mod test { call_ty: meta_type::<()>(), signature_ty: meta_type::<()>(), extra_ty: meta_type::<()>(), - signed_extensions: vec![], + extensions: vec![], }, ty: meta_type::<()>(), apis: vec![], diff --git a/substrate/primitives/metadata-ir/src/types.rs b/substrate/primitives/metadata-ir/src/types.rs index 4ebe8c25a675..199b692fbd8c 100644 --- a/substrate/primitives/metadata-ir/src/types.rs +++ b/substrate/primitives/metadata-ir/src/types.rs @@ -133,6 +133,8 @@ pub struct PalletMetadataIR { pub constants: Vec>, /// Pallet error metadata. pub error: Option>, + /// Config's trait associated types. + pub associated_types: Vec>, /// Define the index of the pallet, this index will be used for the encoding of pallet event, /// call and origin variants. pub index: u8, @@ -153,6 +155,7 @@ impl IntoPortable for PalletMetadataIR { event: self.event.map(|event| event.into_portable(registry)), constants: registry.map_into_portable(self.constants), error: self.error.map(|error| error.into_portable(registry)), + associated_types: registry.map_into_portable(self.associated_types), index: self.index, docs: registry.map_into_portable(self.docs), deprecation_info: self.deprecation_info.into_portable(registry), @@ -175,10 +178,11 @@ pub struct ExtrinsicMetadataIR { pub call_ty: T::Type, /// The type of the extrinsic's signature. pub signature_ty: T::Type, - /// The type of the outermost Extra enum. + /// The type of the outermost Extra/Extensions enum. + // TODO: metadata-v16: remove this, the `implicit` type can be found in `extensions::implicit`. pub extra_ty: T::Type, - /// The signed extensions in the order they appear in the extrinsic. - pub signed_extensions: Vec>, + /// The transaction extensions in the order they appear in the extrinsic. + pub extensions: Vec>, } impl IntoPortable for ExtrinsicMetadataIR { @@ -192,30 +196,53 @@ impl IntoPortable for ExtrinsicMetadataIR { call_ty: registry.register_type(&self.call_ty), signature_ty: registry.register_type(&self.signature_ty), extra_ty: registry.register_type(&self.extra_ty), - signed_extensions: registry.map_into_portable(self.signed_extensions), + extensions: registry.map_into_portable(self.extensions), + } + } +} + +/// Metadata of a pallet's associated type. +#[derive(Clone, PartialEq, Eq, Encode, Debug)] +pub struct PalletAssociatedTypeMetadataIR { + /// The name of the associated type. + pub name: T::String, + /// The type of the associated type. + pub ty: T::Type, + /// The documentation of the associated type. + pub docs: Vec, +} + +impl IntoPortable for PalletAssociatedTypeMetadataIR { + type Output = PalletAssociatedTypeMetadataIR; + + fn into_portable(self, registry: &mut Registry) -> Self::Output { + PalletAssociatedTypeMetadataIR { + name: self.name.into_portable(registry), + ty: registry.register_type(&self.ty), + docs: registry.map_into_portable(self.docs), } } } /// Metadata of an extrinsic's signed extension. #[derive(Clone, PartialEq, Eq, Encode, Debug)] -pub struct SignedExtensionMetadataIR { +pub struct TransactionExtensionMetadataIR { /// The unique signed extension identifier, which may be different from the type name. pub identifier: T::String, /// The type of the signed extension, with the data to be included in the extrinsic. pub ty: T::Type, - /// The type of the additional signed data, with the data to be included in the signed payload - pub additional_signed: T::Type, + /// The type of the implicit data, with the data to be included in the signed payload. + pub implicit: T::Type, } -impl IntoPortable for SignedExtensionMetadataIR { - type Output = SignedExtensionMetadataIR; +impl IntoPortable for TransactionExtensionMetadataIR { + type Output = TransactionExtensionMetadataIR; fn into_portable(self, registry: &mut Registry) -> Self::Output { - SignedExtensionMetadataIR { + TransactionExtensionMetadataIR { identifier: self.identifier.into_portable(registry), ty: registry.register_type(&self.ty), - additional_signed: registry.register_type(&self.additional_signed), + implicit: registry.register_type(&self.implicit), } } } diff --git a/substrate/primitives/metadata-ir/src/v14.rs b/substrate/primitives/metadata-ir/src/v14.rs index e1b7a24f7657..70e84532add9 100644 --- a/substrate/primitives/metadata-ir/src/v14.rs +++ b/substrate/primitives/metadata-ir/src/v14.rs @@ -20,8 +20,8 @@ use super::types::{ ExtrinsicMetadataIR, MetadataIR, PalletCallMetadataIR, PalletConstantMetadataIR, PalletErrorMetadataIR, PalletEventMetadataIR, PalletMetadataIR, PalletStorageMetadataIR, - SignedExtensionMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, - StorageHasherIR, + StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR, + TransactionExtensionMetadataIR, }; use frame_metadata::v14::{ @@ -137,12 +137,12 @@ impl From for PalletErrorMetadata { } } -impl From for SignedExtensionMetadata { - fn from(ir: SignedExtensionMetadataIR) -> Self { +impl From for SignedExtensionMetadata { + fn from(ir: TransactionExtensionMetadataIR) -> Self { SignedExtensionMetadata { identifier: ir.identifier, ty: ir.ty, - additional_signed: ir.additional_signed, + additional_signed: ir.implicit, } } } @@ -152,7 +152,7 @@ impl From for ExtrinsicMetadata { ExtrinsicMetadata { ty: ir.ty, version: ir.version, - signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), + 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 a942eb73223b..4b3b6106d27f 100644 --- a/substrate/primitives/metadata-ir/src/v15.rs +++ b/substrate/primitives/metadata-ir/src/v15.rs @@ -21,7 +21,7 @@ use crate::OuterEnumsIR; use super::types::{ ExtrinsicMetadataIR, MetadataIR, PalletMetadataIR, RuntimeApiMetadataIR, - RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, SignedExtensionMetadataIR, + RuntimeApiMethodMetadataIR, RuntimeApiMethodParamMetadataIR, TransactionExtensionMetadataIR, }; use frame_metadata::v15::{ @@ -87,12 +87,12 @@ impl From for PalletMetadata { } } -impl From for SignedExtensionMetadata { - fn from(ir: SignedExtensionMetadataIR) -> Self { +impl From for SignedExtensionMetadata { + fn from(ir: TransactionExtensionMetadataIR) -> Self { SignedExtensionMetadata { identifier: ir.identifier, ty: ir.ty, - additional_signed: ir.additional_signed, + additional_signed: ir.implicit, } } } @@ -105,7 +105,7 @@ impl From for ExtrinsicMetadata { call_ty: ir.call_ty, signature_ty: ir.signature_ty, extra_ty: ir.extra_ty, - signed_extensions: ir.signed_extensions.into_iter().map(Into::into).collect(), + signed_extensions: ir.extensions.into_iter().map(Into::into).collect(), } } } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index c3413775b1cc..8a812c3a5772 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -39,6 +39,7 @@ 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 } [dev-dependencies] rand = { workspace = true, default-features = true } @@ -75,6 +76,7 @@ std = [ "sp-trie/std", "sp-weights/std", "tracing/std", + "tuplex/std", ] # Serde support without relying on std features. diff --git a/substrate/primitives/runtime/src/generic/block.rs b/substrate/primitives/runtime/src/generic/block.rs index 8ed79c7c8dcf..a084a3703f9e 100644 --- a/substrate/primitives/runtime/src/generic/block.rs +++ b/substrate/primitives/runtime/src/generic/block.rs @@ -99,7 +99,7 @@ where impl traits::Block for Block where Header: HeaderT + MaybeSerializeDeserialize, - Extrinsic: Member + Codec + traits::Extrinsic, + Extrinsic: Member + Codec + traits::ExtrinsicLike, { type Extrinsic = Extrinsic; type Header = Header; diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 44325920beee..1842b1631621 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -18,81 +18,138 @@ //! Generic implementation of an extrinsic that has passed the verification //! stage. +use codec::Encode; +use sp_weights::Weight; + use crate::{ traits::{ - self, DispatchInfoOf, Dispatchable, MaybeDisplay, Member, PostDispatchInfoOf, - SignedExtension, ValidateUnsigned, + self, transaction_extension::TransactionExtension, AsTransactionAuthorizedOrigin, + DispatchInfoOf, DispatchTransaction, Dispatchable, MaybeDisplay, Member, + PostDispatchInfoOf, ValidateUnsigned, }, 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)] +pub enum ExtrinsicFormat { + /// Extrinsic is bare; it must pass either the bare forms of `TransactionExtension` or + /// `ValidateUnsigned`, both deprecated, or alternatively a `ProvideInherent`. + Bare, + /// Extrinsic has a default `Origin` of `Signed(AccountId)` and must pass all + /// `TransactionExtension`s regular checks and includes all extension data. + Signed(AccountId, Extension), + /// Extrinsic has a default `Origin` of `None` and must pass all `TransactionExtension`s. + /// regular checks and includes all extension data. + General(ExtensionVersion, Extension), +} + /// Definition of something that the external world might want to say; its existence implies that it /// has been checked and is good, particularly with regards to the signature. /// /// This is typically passed into [`traits::Applyable::apply`], which should execute /// [`CheckedExtrinsic::function`], alongside all other bits and bobs. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] -pub struct CheckedExtrinsic { +pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub signed: Option<(AccountId, Extra)>, + pub format: ExtrinsicFormat, /// The function that should be called. pub function: Call, } -impl traits::Applyable - for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, - Call: Member + Dispatchable, - Extra: SignedExtension, - RuntimeOrigin: From>, + Call: Member + Dispatchable + Encode, + Extension: TransactionExtension, + RuntimeOrigin: From> + AsTransactionAuthorizedOrigin, { type Call = Call; - fn validate>( + fn validate>( &self, - // TODO [#5006;ToDr] should source be passed to `SignedExtension`s? - // Perhaps a change for 2.0 to avoid breaking too much APIs? source: TransactionSource, info: &DispatchInfoOf, len: usize, ) -> TransactionValidity { - if let Some((ref id, ref extra)) = self.signed { - Extra::validate(extra, id, &self.function, info, len) - } else { - let valid = Extra::validate_unsigned(&self.function, info, len)?; - let unsigned_validation = U::validate_unsigned(source, &self.function)?; - Ok(valid.combine_with(unsigned_validation)) + match self.format { + ExtrinsicFormat::Bare => { + let inherent_validation = I::validate_unsigned(source, &self.function)?; + #[allow(deprecated)] + let legacy_validation = Extension::bare_validate(&self.function, info, len)?; + Ok(legacy_validation.combine_with(inherent_validation)) + }, + ExtrinsicFormat::Signed(ref signer, ref extension) => { + let origin = Some(signer.clone()).into(); + extension + .validate_only( + origin, + &self.function, + info, + len, + source, + DEFAULT_EXTENSION_VERSION, + ) + .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), } } - fn apply>( + fn apply>( self, info: &DispatchInfoOf, len: usize, ) -> crate::ApplyExtrinsicResultWithInfo> { - let (maybe_who, maybe_pre) = if let Some((id, extra)) = self.signed { - let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?; - (Some(id), Some(pre)) - } else { - Extra::pre_dispatch_unsigned(&self.function, info, len)?; - U::pre_dispatch(&self.function)?; - (None, None) - }; - let res = self.function.dispatch(RuntimeOrigin::from(maybe_who)); - let post_info = match res { - Ok(info) => info, - Err(err) => err.post_info, - }; - Extra::post_dispatch( - maybe_pre, - info, - &post_info, - len, - &res.map(|_| ()).map_err(|e| e.error), - )?; - Ok(res) + match self.format { + ExtrinsicFormat::Bare => { + I::pre_dispatch(&self.function)?; + // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` + // interface. + Extension::bare_validate_and_prepare(&self.function, info, len)?; + let res = self.function.dispatch(None.into()); + let mut post_info = res.unwrap_or_else(|err| err.post_info); + let pd_res = res.map(|_| ()).map_err(|e| e.error); + // TODO: Separate logic from `TransactionExtension` into a new `InherentExtension` + // interface. + 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, + DEFAULT_EXTENSION_VERSION, + ), + ExtrinsicFormat::General(extension_version, extension) => extension + .dispatch_transaction(None.into(), self.function, info, len, extension_version), + } + } +} + +impl> + CheckedExtrinsic +{ + /// Returns the weight of the extension of this transaction, if present. If the transaction + /// doesn't use any extension, the weight returned is equal to zero. + pub fn extension_weight(&self) -> Weight { + match &self.format { + ExtrinsicFormat::Bare => Weight::zero(), + 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 3687f7cdb3b2..f79058e270ed 100644 --- a/substrate/primitives/runtime/src/generic/mod.rs +++ b/substrate/primitives/runtime/src/generic/mod.rs @@ -16,7 +16,7 @@ // limitations under the License. //! Generic implementations of [`crate::traits::Header`], [`crate::traits::Block`] and -//! [`crate::traits::Extrinsic`]. +//! [`crate::traits::ExtrinsicLike`]. mod block; mod checked_extrinsic; @@ -29,9 +29,12 @@ mod unchecked_extrinsic; pub use self::{ block::{Block, BlockId, SignedBlock}, - checked_extrinsic::CheckedExtrinsic, + checked_extrinsic::{CheckedExtrinsic, ExtrinsicFormat}, digest::{Digest, DigestItem, DigestItemRef, OpaqueDigestItemId}, era::{Era, Phase}, header::Header, - unchecked_extrinsic::{SignedPayload, UncheckedExtrinsic}, + 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 499b7c5f5836..91ba37451909 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -18,10 +18,10 @@ //! Generic implementation of an unchecked (pre-verification) extrinsic. use crate::{ - generic::CheckedExtrinsic, + generic::{CheckedExtrinsic, ExtrinsicFormat}, traits::{ - self, Checkable, Extrinsic, ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, - SignaturePayload, SignedExtension, + self, transaction_extension::TransactionExtension, Checkable, Dispatchable, ExtrinsicLike, + ExtrinsicMetadata, IdentifyAccount, MaybeDisplay, Member, SignaturePayload, }, transaction_validity::{InvalidTransaction, TransactionValidityError}, OpaqueExtrinsic, @@ -33,16 +33,169 @@ use codec::{Compact, Decode, Encode, EncodeLike, Error, Input}; use core::fmt; use scale_info::{build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, TypeParameter}; use sp_io::hashing::blake2_256; +use sp_weights::Weight; + +/// Type to represent the version of the [Extension](TransactionExtension) used in this extrinsic. +pub type ExtensionVersion = u8; +/// Type to represent the extrinsic format version which defines an [UncheckedExtrinsic]. +pub type ExtrinsicVersion = u8; /// Current version of the [`UncheckedExtrinsic`] encoded format. /// /// This version needs to be bumped if the encoded representation changes. /// It ensures that if the representation is changed and the format is not known, /// the decoding fails. -const EXTRINSIC_FORMAT_VERSION: u8 = 4; +pub const EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 5; +/// Legacy version of the [`UncheckedExtrinsic`] encoded format. +/// +/// This version was used in the signed/unsigned transaction model and is still supported for +/// compatibility reasons. It will be deprecated in favor of v5 extrinsics and an inherent/general +/// transaction model. +pub const LEGACY_EXTRINSIC_FORMAT_VERSION: ExtrinsicVersion = 4; +/// Current version of the [Extension](TransactionExtension) used in this +/// [extrinsic](UncheckedExtrinsic). +/// +/// This version needs to be bumped if there are breaking changes to the extension used in the +/// [UncheckedExtrinsic] implementation. +const EXTENSION_VERSION: ExtensionVersion = 0; /// The `SignaturePayload` of `UncheckedExtrinsic`. -type UncheckedSignaturePayload = (Address, Signature, Extra); +pub type UncheckedSignaturePayload = (Address, Signature, Extension); + +impl SignaturePayload + for UncheckedSignaturePayload +{ + type SignatureAddress = Address; + type Signature = Signature; + type SignatureExtra = Extension; +} + +/// A "header" for extrinsics leading up to the call itself. Determines the type of extrinsic and +/// holds any necessary specialized data. +#[derive(Eq, PartialEq, Clone)] +pub enum Preamble { + /// An extrinsic without a signature or any extension. This means it's either an inherent or + /// an old-school "Unsigned" (we don't use that terminology any more since it's confusable with + /// the general transaction which is without a signature but does have an extension). + /// + /// NOTE: In the future, once we remove `ValidateUnsigned`, this will only serve Inherent + /// extrinsics and thus can be renamed to `Inherent`. + 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, 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. + General(ExtensionVersion, Extension), +} + +const VERSION_MASK: u8 = 0b0011_1111; +const TYPE_MASK: u8 = 0b1100_0000; +const BARE_EXTRINSIC: u8 = 0b0000_0000; +const SIGNED_EXTRINSIC: u8 = 0b1000_0000; +const GENERAL_EXTRINSIC: u8 = 0b0100_0000; + +impl Decode for Preamble +where + Address: Decode, + Signature: Decode, + Extension: Decode, +{ + fn decode(input: &mut I) -> Result { + let version_and_type = input.read_byte()?; + + let version = version_and_type & VERSION_MASK; + let xt_type = version_and_type & TYPE_MASK; + + let preamble = match (version, xt_type) { + ( + extrinsic_version @ LEGACY_EXTRINSIC_FORMAT_VERSION..=EXTRINSIC_FORMAT_VERSION, + BARE_EXTRINSIC, + ) => Self::Bare(extrinsic_version), + (LEGACY_EXTRINSIC_FORMAT_VERSION, SIGNED_EXTRINSIC) => { + let address = Address::decode(input)?; + let signature = Signature::decode(input)?; + let ext = Extension::decode(input)?; + Self::Signed(address, signature, ext) + }, + (EXTRINSIC_FORMAT_VERSION, GENERAL_EXTRINSIC) => { + let ext_version = ExtensionVersion::decode(input)?; + let ext = Extension::decode(input)?; + Self::General(ext_version, ext) + }, + (_, _) => return Err("Invalid transaction version".into()), + }; + + Ok(preamble) + } +} + +impl Encode for Preamble +where + Address: Encode, + Signature: Encode, + Extension: Encode, +{ + fn size_hint(&self) -> usize { + match &self { + Preamble::Bare(_) => EXTRINSIC_FORMAT_VERSION.size_hint(), + Preamble::Signed(address, signature, ext) => LEGACY_EXTRINSIC_FORMAT_VERSION + .size_hint() + .saturating_add(address.size_hint()) + .saturating_add(signature.size_hint()) + .saturating_add(ext.size_hint()), + Preamble::General(ext_version, ext) => EXTRINSIC_FORMAT_VERSION + .size_hint() + .saturating_add(ext_version.size_hint()) + .saturating_add(ext.size_hint()), + } + } + + fn encode_to(&self, dest: &mut T) { + match &self { + Preamble::Bare(extrinsic_version) => { + (extrinsic_version | BARE_EXTRINSIC).encode_to(dest); + }, + Preamble::Signed(address, signature, ext) => { + (LEGACY_EXTRINSIC_FORMAT_VERSION | SIGNED_EXTRINSIC).encode_to(dest); + address.encode_to(dest); + signature.encode_to(dest); + ext.encode_to(dest); + }, + Preamble::General(ext_version, ext) => { + (EXTRINSIC_FORMAT_VERSION | GENERAL_EXTRINSIC).encode_to(dest); + ext_version.encode_to(dest); + ext.encode_to(dest); + }, + } + } +} + +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)), + _ => None, + } + } +} + +impl fmt::Debug for Preamble +where + Address: fmt::Debug, + Extension: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Bare(_) => write!(f, "Bare"), + Self::Signed(address, _, tx_ext) => write!(f, "Signed({:?}, {:?})", address, tx_ext), + Self::General(ext_version, tx_ext) => + write!(f, "General({:?}, {:?})", ext_version, tx_ext), + } + } +} /// An extrinsic right from the external world. This is unchecked and so can contain a signature. /// @@ -66,41 +219,28 @@ type UncheckedSignaturePayload = (Address, Signature, /// This can be checked using [`Checkable`], yielding a [`CheckedExtrinsic`], which is the /// counterpart of this type after its signature (and other non-negotiable validity checks) have /// passed. -#[derive(PartialEq, Eq, Clone)] -pub struct UncheckedExtrinsic -where - Extra: SignedExtension, -{ - /// The signature, address, number of extrinsics have come before from the same signer and an - /// era describing the longevity of this transaction, if this is a signed extrinsic. - /// - /// `None` if it is unsigned or an inherent. - pub signature: Option>, +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct UncheckedExtrinsic { + /// Information regarding the type of extrinsic this is (inherent or transaction) as well as + /// associated extension (`Extension`) data if it's a transaction and a possible signature. + pub preamble: Preamble, /// The function that should be called. pub function: Call, } -impl SignaturePayload - for UncheckedSignaturePayload -{ - type SignatureAddress = Address; - type Signature = Signature; - type SignatureExtra = Extra; -} - /// Manual [`TypeInfo`] implementation because of custom encoding. The data is a valid encoded /// `Vec`, but requires some logic to extract the signature and payload. /// /// See [`UncheckedExtrinsic::encode`] and [`UncheckedExtrinsic::decode`]. -impl TypeInfo - for UncheckedExtrinsic +impl TypeInfo + for UncheckedExtrinsic where Address: StaticTypeInfo, Call: StaticTypeInfo, Signature: StaticTypeInfo, - Extra: SignedExtension + StaticTypeInfo, + Extension: StaticTypeInfo, { - type Identity = UncheckedExtrinsic; + type Identity = UncheckedExtrinsic; fn type_info() -> Type { Type::builder() @@ -112,7 +252,7 @@ where TypeParameter::new("Address", Some(meta_type::
())), TypeParameter::new("Call", Some(meta_type::())), TypeParameter::new("Signature", Some(meta_type::())), - TypeParameter::new("Extra", Some(meta_type::())), + TypeParameter::new("Extra", Some(meta_type::())), ]) .docs(&["UncheckedExtrinsic raw bytes, requires custom decoding routine"]) // Because of the custom encoding, we can only accurately describe the encoding as an @@ -122,66 +262,104 @@ where } } -impl - UncheckedExtrinsic -{ - /// New instance of a signed extrinsic aka "transaction". - pub fn new_signed(function: Call, signed: Address, signature: Signature, extra: Extra) -> Self { - Self { signature: Some((signed, signature, extra)), function } +impl UncheckedExtrinsic { + /// New instance of a bare (ne unsigned) extrinsic. This could be used for an inherent or an + /// old-school "unsigned transaction" (which are new being deprecated in favour of general + /// transactions). + #[deprecated = "Use new_bare instead"] + pub fn new_unsigned(function: Call) -> Self { + Self::new_bare(function) } - /// New instance of an unsigned extrinsic aka "inherent". - pub fn new_unsigned(function: Call) -> Self { - Self { signature: None, function } + /// Returns `true` if this extrinsic instance is an inherent, `false`` otherwise. + pub fn is_inherent(&self) -> bool { + matches!(self.preamble, Preamble::Bare(_)) } -} -impl - Extrinsic for UncheckedExtrinsic -{ - type Call = Call; + /// Returns `true` if this extrinsic instance is an old-school signed transaction, `false` + /// otherwise. + pub fn is_signed(&self) -> bool { + matches!(self.preamble, Preamble::Signed(..)) + } - type SignaturePayload = UncheckedSignaturePayload; + /// Create an `UncheckedExtrinsic` from a `Preamble` and the actual `Call`. + pub fn from_parts(function: Call, preamble: Preamble) -> Self { + Self { preamble, function } + } - fn is_signed(&self) -> Option { - Some(self.signature.is_some()) + /// New instance of a bare (ne unsigned) extrinsic. + pub fn new_bare(function: Call) -> Self { + Self { preamble: Preamble::Bare(EXTRINSIC_FORMAT_VERSION), function } } - fn new(function: Call, signed_data: Option) -> Option { - Some(if let Some((address, signature, extra)) = signed_data { - Self::new_signed(function, address, signature, extra) - } else { - Self::new_unsigned(function) - }) + /// New instance of a bare (ne unsigned) extrinsic on extrinsic format version 4. + pub fn new_bare_legacy(function: Call) -> Self { + Self { preamble: Preamble::Bare(LEGACY_EXTRINSIC_FORMAT_VERSION), function } + } + + /// New instance of an old-school signed transaction on extrinsic format version 4. + pub fn new_signed( + function: Call, + signed: Address, + signature: Signature, + tx_ext: Extension, + ) -> Self { + Self { preamble: Preamble::Signed(signed, signature, tx_ext), function } + } + + /// New instance of an new-school unsigned transaction. + pub fn new_transaction(function: Call, tx_ext: Extension) -> Self { + Self { preamble: Preamble::General(EXTENSION_VERSION, tx_ext), function } + } +} + +impl ExtrinsicLike + for UncheckedExtrinsic +{ + fn is_bare(&self) -> bool { + matches!(self.preamble, Preamble::Bare(_)) + } + + fn is_signed(&self) -> Option { + Some(matches!(self.preamble, Preamble::Signed(..))) } } -impl Checkable - for UncheckedExtrinsic +// TODO: Migrate existing extension pipelines to support current `Signed` transactions as `General` +// transactions by adding an extension to validate signatures, as they are currently validated in +// the `Checkable` implementation for `Signed` transactions. + +impl Checkable + for UncheckedExtrinsic where LookupSource: Member + MaybeDisplay, - Call: Encode + Member, + Call: Encode + Member + Dispatchable, Signature: Member + traits::Verify, ::Signer: IdentifyAccount, - Extra: SignedExtension, + Extension: Encode + TransactionExtension, AccountId: Member + MaybeDisplay, Lookup: traits::Lookup, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, lookup: &Lookup) -> Result { - Ok(match self.signature { - Some((signed, signature, extra)) => { + Ok(match self.preamble { + Preamble::Signed(signed, signature, tx_ext) => { let signed = lookup.lookup(signed)?; - let raw_payload = SignedPayload::new(self.function, extra)?; + // The `Implicit` is "implicitly" included in the payload. + let raw_payload = SignedPayload::new(self.function, tx_ext)?; if !raw_payload.using_encoded(|payload| signature.verify(payload, &signed)) { return Err(InvalidTransaction::BadProof.into()) } - - let (function, extra, _) = raw_payload.deconstruct(); - CheckedExtrinsic { signed: Some((signed, extra)), function } + let (function, tx_ext, _) = raw_payload.deconstruct(); + CheckedExtrinsic { format: ExtrinsicFormat::Signed(signed, tx_ext), function } + }, + Preamble::General(extension_version, tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(extension_version, tx_ext), + function: self.function, }, - None => CheckedExtrinsic { signed: None, function: self.function }, + Preamble::Bare(_) => + CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }, }) } @@ -190,91 +368,52 @@ where self, lookup: &Lookup, ) -> Result { - Ok(match self.signature { - Some((signed, _, extra)) => { + Ok(match self.preamble { + Preamble::Signed(signed, _, tx_ext) => { let signed = lookup.lookup(signed)?; - let raw_payload = SignedPayload::new(self.function, extra)?; - let (function, extra, _) = raw_payload.deconstruct(); - CheckedExtrinsic { signed: Some((signed, extra)), function } + CheckedExtrinsic { + format: ExtrinsicFormat::Signed(signed, tx_ext), + function: self.function, + } + }, + Preamble::General(extension_version, tx_ext) => CheckedExtrinsic { + format: ExtrinsicFormat::General(extension_version, tx_ext), + function: self.function, }, - None => CheckedExtrinsic { signed: None, function: self.function }, + Preamble::Bare(_) => + CheckedExtrinsic { format: ExtrinsicFormat::Bare, function: self.function }, }) } } -impl ExtrinsicMetadata - for UncheckedExtrinsic -where - Extra: SignedExtension, +impl> + ExtrinsicMetadata for UncheckedExtrinsic { - const VERSION: u8 = EXTRINSIC_FORMAT_VERSION; - type SignedExtensions = Extra; + // TODO: Expose both version 4 and version 5 in metadata v16. + const VERSION: u8 = LEGACY_EXTRINSIC_FORMAT_VERSION; + type TransactionExtensions = Extension; } -/// A payload that has been signed for an unchecked extrinsics. -/// -/// Note that the payload that we sign to produce unchecked extrinsic signature -/// is going to be different than the `SignaturePayload` - so the thing the extrinsic -/// actually contains. -pub struct SignedPayload((Call, Extra, Extra::AdditionalSigned)); - -impl SignedPayload -where - Call: Encode, - Extra: SignedExtension, +impl> + UncheckedExtrinsic { - /// Create new `SignedPayload`. - /// - /// This function may fail if `additional_signed` of `Extra` is not available. - pub fn new(call: Call, extra: Extra) -> Result { - let additional_signed = extra.additional_signed()?; - let raw_payload = (call, extra, additional_signed); - Ok(Self(raw_payload)) - } - - /// Create new `SignedPayload` from raw components. - pub fn from_raw(call: Call, extra: Extra, additional_signed: Extra::AdditionalSigned) -> Self { - Self((call, extra, additional_signed)) - } - - /// Deconstruct the payload into it's components. - pub fn deconstruct(self) -> (Call, Extra, Extra::AdditionalSigned) { - self.0 - } -} - -impl Encode for SignedPayload -where - Call: Encode, - Extra: SignedExtension, -{ - /// Get an encoded version of this payload. - /// - /// Payloads longer than 256 bytes are going to be `blake2_256`-hashed. - fn using_encoded R>(&self, f: F) -> R { - self.0.using_encoded(|payload| { - if payload.len() > 256 { - f(&blake2_256(payload)[..]) - } else { - f(payload) - } - }) + /// Returns the weight of the extension of this transaction, if present. If the transaction + /// doesn't use any extension, the weight returned is equal to zero. + pub fn extension_weight(&self) -> Weight { + match &self.preamble { + Preamble::Bare(_) => Weight::zero(), + Preamble::Signed(_, _, ext) | Preamble::General(_, ext) => ext.weight(&self.function), + } } } -impl EncodeLike for SignedPayload -where - Call: Encode, - Extra: SignedExtension, -{ -} - -impl Decode for UncheckedExtrinsic +impl Decode + for UncheckedExtrinsic where Address: Decode, Signature: Decode, Call: Decode, - Extra: SignedExtension, + Extension: Decode, { fn decode(input: &mut I) -> Result { // This is a little more complicated than usual since the binary format must be compatible @@ -283,15 +422,7 @@ where let expected_length: Compact = Decode::decode(input)?; let before_length = input.remaining_len()?; - let version = input.read_byte()?; - - let is_signed = version & 0b1000_0000 != 0; - let version = version & 0b0111_1111; - if version != EXTRINSIC_FORMAT_VERSION { - return Err("Invalid transaction version".into()) - } - - let signature = is_signed.then(|| Decode::decode(input)).transpose()?; + let preamble = Decode::decode(input)?; let function = Decode::decode(input)?; if let Some((before_length, after_length)) = @@ -304,31 +435,20 @@ where } } - Ok(Self { signature, function }) + Ok(Self { preamble, function }) } } #[docify::export(unchecked_extrinsic_encode_impl)] -impl Encode for UncheckedExtrinsic +impl Encode + for UncheckedExtrinsic where - Address: Encode, - Signature: Encode, + Preamble: Encode, Call: Encode, - Extra: SignedExtension, + Extension: Encode, { fn encode(&self) -> Vec { - let mut tmp = Vec::with_capacity(core::mem::size_of::()); - - // 1 byte version id. - match self.signature.as_ref() { - Some(s) => { - tmp.push(EXTRINSIC_FORMAT_VERSION | 0b1000_0000); - s.encode_to(&mut tmp); - }, - None => { - tmp.push(EXTRINSIC_FORMAT_VERSION & 0b0111_1111); - }, - } + let mut tmp = self.preamble.encode(); self.function.encode_to(&mut tmp); let compact_len = codec::Compact::(tmp.len() as u32); @@ -343,19 +463,19 @@ where } } -impl EncodeLike - for UncheckedExtrinsic +impl EncodeLike + for UncheckedExtrinsic where Address: Encode, Signature: Encode, - Call: Encode, - Extra: SignedExtension, + Call: Encode + Dispatchable, + Extension: TransactionExtension, { } #[cfg(feature = "serde")] -impl serde::Serialize - for UncheckedExtrinsic +impl serde::Serialize + for UncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where @@ -366,45 +486,86 @@ impl s } #[cfg(feature = "serde")] -impl<'a, Address: Decode, Signature: Decode, Call: Decode, Extra: SignedExtension> - serde::Deserialize<'a> for UncheckedExtrinsic +impl<'a, Address: Decode, Signature: Decode, Call: Decode, Extension: Decode> serde::Deserialize<'a> + for UncheckedExtrinsic { fn deserialize(de: D) -> Result where D: serde::Deserializer<'a>, { let r = sp_core::bytes::deserialize(de)?; - Decode::decode(&mut &r[..]) + Self::decode(&mut &r[..]) .map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e))) } } -impl fmt::Debug - for UncheckedExtrinsic +/// A payload that has been signed for an unchecked extrinsics. +/// +/// Note that the payload that we sign to produce unchecked extrinsic signature +/// is going to be different than the `SignaturePayload` - so the thing the extrinsic +/// actually contains. +pub struct SignedPayload>( + (Call, Extension, Extension::Implicit), +); + +impl SignedPayload where - Address: fmt::Debug, - Call: fmt::Debug, - Extra: SignedExtension, + Call: Encode + Dispatchable, + Extension: TransactionExtension, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "UncheckedExtrinsic({:?}, {:?})", - self.signature.as_ref().map(|x| (&x.0, &x.2)), - self.function, - ) + /// Create new `SignedPayload` for extrinsic format version 4. + /// + /// This function may fail if `implicit` of `Extension` is not available. + pub fn new(call: Call, tx_ext: Extension) -> Result { + let implicit = Extension::implicit(&tx_ext)?; + let raw_payload = (call, tx_ext, implicit); + Ok(Self(raw_payload)) + } + + /// Create new `SignedPayload` from raw components. + pub fn from_raw(call: Call, tx_ext: Extension, implicit: Extension::Implicit) -> Self { + Self((call, tx_ext, implicit)) + } + + /// Deconstruct the payload into it's components. + pub fn deconstruct(self) -> (Call, Extension, Extension::Implicit) { + self.0 + } +} + +impl Encode for SignedPayload +where + Call: Encode + Dispatchable, + Extension: TransactionExtension, +{ + /// Get an encoded version of this `blake2_256`-hashed payload. + fn using_encoded R>(&self, f: F) -> R { + self.0.using_encoded(|payload| { + if payload.len() > 256 { + f(&blake2_256(payload)[..]) + } else { + f(payload) + } + }) } } -impl From> - for OpaqueExtrinsic +impl EncodeLike for SignedPayload +where + Call: Encode + Dispatchable, + Extension: TransactionExtension, +{ +} + +impl + From> for OpaqueExtrinsic where Address: Encode, Signature: Encode, Call: Encode, - Extra: SignedExtension, + Extension: Encode, { - fn from(extrinsic: UncheckedExtrinsic) -> Self { + fn from(extrinsic: UncheckedExtrinsic) -> Self { Self::from_bytes(extrinsic.encode().as_slice()).expect( "both OpaqueExtrinsic and UncheckedExtrinsic have encoding that is compatible with \ raw Vec encoding; qed", @@ -412,60 +573,196 @@ where } } +#[cfg(test)] +mod legacy { + use codec::{Compact, Decode, Encode, EncodeLike, Error, Input}; + use scale_info::{ + build::Fields, meta_type, Path, StaticTypeInfo, Type, TypeInfo, TypeParameter, + }; + + pub type UncheckedSignaturePayloadV4 = (Address, Signature, Extra); + + #[derive(PartialEq, Eq, Clone, Debug)] + pub struct UncheckedExtrinsicV4 { + pub signature: Option>, + pub function: Call, + } + + impl TypeInfo + for UncheckedExtrinsicV4 + where + Address: StaticTypeInfo, + Call: StaticTypeInfo, + Signature: StaticTypeInfo, + Extra: StaticTypeInfo, + { + type Identity = UncheckedExtrinsicV4; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("UncheckedExtrinsic", module_path!())) + // Include the type parameter types, even though they are not used directly in any + // of the described fields. These type definitions can be used by downstream + // consumers to help construct the custom decoding from the opaque bytes (see + // below). + .type_params(vec![ + TypeParameter::new("Address", Some(meta_type::
())), + TypeParameter::new("Call", Some(meta_type::())), + TypeParameter::new("Signature", Some(meta_type::())), + TypeParameter::new("Extra", Some(meta_type::())), + ]) + .docs(&["OldUncheckedExtrinsic raw bytes, requires custom decoding routine"]) + // Because of the custom encoding, we can only accurately describe the encoding as + // an opaque `Vec`. Downstream consumers will need to manually implement the + // codec to encode/decode the `signature` and `function` fields. + .composite(Fields::unnamed().field(|f| f.ty::>())) + } + } + + impl UncheckedExtrinsicV4 { + pub fn new_signed( + function: Call, + signed: Address, + signature: Signature, + extra: Extra, + ) -> Self { + Self { signature: Some((signed, signature, extra)), function } + } + + pub fn new_unsigned(function: Call) -> Self { + Self { signature: None, function } + } + } + + impl Decode + for UncheckedExtrinsicV4 + where + Address: Decode, + Signature: Decode, + Call: Decode, + Extra: Decode, + { + fn decode(input: &mut I) -> Result { + // This is a little more complicated than usual since the binary format must be + // compatible with SCALE's generic `Vec` type. Basically this just means accepting + // that there will be a prefix of vector length. + let expected_length: Compact = Decode::decode(input)?; + let before_length = input.remaining_len()?; + + let version = input.read_byte()?; + + let is_signed = version & 0b1000_0000 != 0; + let version = version & 0b0111_1111; + if version != 4u8 { + return Err("Invalid transaction version".into()) + } + + let signature = is_signed.then(|| Decode::decode(input)).transpose()?; + let function = Decode::decode(input)?; + + if let Some((before_length, after_length)) = + input.remaining_len()?.and_then(|a| before_length.map(|b| (b, a))) + { + let length = before_length.saturating_sub(after_length); + + if length != expected_length.0 as usize { + return Err("Invalid length prefix".into()) + } + } + + Ok(Self { signature, function }) + } + } + + #[docify::export(unchecked_extrinsic_encode_impl)] + impl Encode + for UncheckedExtrinsicV4 + where + Address: Encode, + Signature: Encode, + Call: Encode, + Extra: Encode, + { + fn encode(&self) -> Vec { + let mut tmp = Vec::with_capacity(sp_std::mem::size_of::()); + + // 1 byte version id. + match self.signature.as_ref() { + Some(s) => { + tmp.push(4u8 | 0b1000_0000); + s.encode_to(&mut tmp); + }, + None => { + tmp.push(4u8 & 0b0111_1111); + }, + } + self.function.encode_to(&mut tmp); + + let compact_len = codec::Compact::(tmp.len() as u32); + + // Allocate the output buffer with the correct length + let mut output = Vec::with_capacity(compact_len.size_hint() + tmp.len()); + + compact_len.encode_to(&mut output); + output.extend(tmp); + + output + } + } + + impl EncodeLike + for UncheckedExtrinsicV4 + where + Address: Encode, + Signature: Encode, + Call: Encode, + Extra: Encode, + { + } +} + #[cfg(test)] mod tests { - use super::*; + use super::{legacy::UncheckedExtrinsicV4, *}; use crate::{ codec::{Decode, Encode}, + impl_tx_ext_default, testing::TestSignature as TestSig, - traits::{DispatchInfoOf, IdentityLookup, SignedExtension}, + traits::{FakeDispatchable, IdentityLookup, TransactionExtension}, }; use sp_io::hashing::blake2_256; type TestContext = IdentityLookup; type TestAccountId = u64; - type TestCall = Vec; + type TestCall = FakeDispatchable>; const TEST_ACCOUNT: TestAccountId = 0; // NOTE: this is demonstration. One can simply use `()` for testing. #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd, TypeInfo)] - struct TestExtra; - impl SignedExtension for TestExtra { - const IDENTIFIER: &'static str = "TestExtra"; - type AccountId = u64; - type Call = (); - type AdditionalSigned = (); + struct DummyExtension; + impl TransactionExtension for DummyExtension { + const IDENTIFIER: &'static str = "DummyExtension"; + type Implicit = (); + type Val = (); type Pre = (); - - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) - } + impl_tx_ext_default!(TestCall; weight validate prepare); } - type Ex = UncheckedExtrinsic; - type CEx = CheckedExtrinsic; + type Ex = UncheckedExtrinsic; + type CEx = CheckedExtrinsic; #[test] fn unsigned_codec_should_work() { - let ux = Ex::new_unsigned(vec![0u8; 0]); + let call: TestCall = vec![0u8; 0].into(); + let ux = Ex::new_bare(call); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); } #[test] fn invalid_length_prefix_is_detected() { - let ux = Ex::new_unsigned(vec![0u8; 0]); + let ux = Ex::new_bare(vec![0u8; 0].into()); let mut encoded = ux.encode(); let length = Compact::::decode(&mut &encoded[..]).unwrap(); @@ -474,13 +771,20 @@ mod tests { assert_eq!(Ex::decode(&mut &encoded[..]), Err("Invalid length prefix".into())); } + #[test] + fn transaction_codec_should_work() { + let ux = Ex::new_transaction(vec![0u8; 0].into(), DummyExtension); + let encoded = ux.encode(); + assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); + } + #[test] fn signed_codec_should_work() { let ux = Ex::new_signed( - vec![0u8; 0], + vec![0u8; 0].into(), TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()), - TestExtra, + TestSig(TEST_ACCOUNT, (vec![0u8; 0], DummyExtension).encode()), + DummyExtension, ); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); @@ -489,13 +793,13 @@ mod tests { #[test] fn large_signed_codec_should_work() { let ux = Ex::new_signed( - vec![0u8; 0], + vec![0u8; 0].into(), TEST_ACCOUNT, TestSig( TEST_ACCOUNT, - (vec![0u8; 257], TestExtra).using_encoded(blake2_256)[..].to_owned(), + (vec![0u8; 257], DummyExtension).using_encoded(blake2_256)[..].to_owned(), ), - TestExtra, + DummyExtension, ); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux)); @@ -503,44 +807,68 @@ mod tests { #[test] fn unsigned_check_should_work() { - let ux = Ex::new_unsigned(vec![0u8; 0]); - assert!(!ux.is_signed().unwrap_or(false)); - assert!(>::check(ux, &Default::default()).is_ok()); + let ux = Ex::new_bare(vec![0u8; 0].into()); + assert!(ux.is_inherent()); + assert_eq!( + >::check(ux, &Default::default()), + Ok(CEx { format: ExtrinsicFormat::Bare, function: vec![0u8; 0].into() }), + ); } #[test] fn badly_signed_check_should_fail() { let ux = Ex::new_signed( - vec![0u8; 0], + vec![0u8; 0].into(), TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, vec![0u8; 0]), - TestExtra, + TestSig(TEST_ACCOUNT, vec![0u8; 0].into()), + DummyExtension, ); - assert!(ux.is_signed().unwrap_or(false)); + assert!(!ux.is_inherent()); assert_eq!( >::check(ux, &Default::default()), Err(InvalidTransaction::BadProof.into()), ); } + #[test] + fn transaction_check_should_work() { + let ux = Ex::new_transaction(vec![0u8; 0].into(), DummyExtension); + assert!(!ux.is_inherent()); + assert_eq!( + >::check(ux, &Default::default()), + Ok(CEx { + format: ExtrinsicFormat::General(0, DummyExtension), + function: vec![0u8; 0].into() + }), + ); + } + #[test] fn signed_check_should_work() { + let sig_payload = SignedPayload::from_raw( + FakeDispatchable::from(vec![0u8; 0]), + DummyExtension, + DummyExtension.implicit().unwrap(), + ); let ux = Ex::new_signed( - vec![0u8; 0], + vec![0u8; 0].into(), TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()), - TestExtra, + TestSig(TEST_ACCOUNT, sig_payload.encode()), + DummyExtension, ); - assert!(ux.is_signed().unwrap_or(false)); + assert!(!ux.is_inherent()); assert_eq!( >::check(ux, &Default::default()), - Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] }), + Ok(CEx { + format: ExtrinsicFormat::Signed(TEST_ACCOUNT, DummyExtension), + function: vec![0u8; 0].into() + }), ); } #[test] fn encoding_matches_vec() { - let ex = Ex::new_unsigned(vec![0u8; 0]); + let ex = Ex::new_bare(vec![0u8; 0].into()); let encoded = ex.encode(); let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); assert_eq!(decoded, ex); @@ -550,7 +878,7 @@ mod tests { #[test] fn conversion_to_opaque() { - let ux = Ex::new_unsigned(vec![0u8; 0]); + let ux = Ex::new_bare(vec![0u8; 0].into()); let encoded = ux.encode(); let opaque: OpaqueExtrinsic = ux.into(); let opaque_encoded = opaque.encode(); @@ -559,10 +887,106 @@ mod tests { #[test] fn large_bad_prefix_should_work() { - let encoded = Compact::::from(u32::MAX).encode(); + let encoded = (Compact::::from(u32::MAX), Preamble::<(), (), ()>::Bare(0)).encode(); + assert!(Ex::decode(&mut &encoded[..]).is_err()); + } + + #[test] + fn legacy_short_signed_encode_decode() { + let call: TestCall = vec![0u8; 4].into(); + let signed = TEST_ACCOUNT; + let extension = DummyExtension; + let implicit = extension.implicit().unwrap(); + let legacy_signature = TestSig(TEST_ACCOUNT, (&call, &extension, &implicit).encode()); + + let old_ux = + UncheckedExtrinsicV4::::new_signed( + call.clone(), + signed, + legacy_signature.clone(), + extension.clone(), + ); + + let encoded_old_ux = old_ux.encode(); + let decoded_old_ux = Ex::decode(&mut &encoded_old_ux[..]).unwrap(); + + assert_eq!(decoded_old_ux.function, call); assert_eq!( - Ex::decode(&mut &encoded[..]), - Err(Error::from("Not enough data to fill buffer")) + decoded_old_ux.preamble, + Preamble::Signed(signed, legacy_signature.clone(), extension.clone()) ); + + let new_ux = + Ex::new_signed(call.clone(), signed, legacy_signature.clone(), extension.clone()); + + let new_checked = new_ux.check(&IdentityLookup::::default()).unwrap(); + let old_checked = + decoded_old_ux.check(&IdentityLookup::::default()).unwrap(); + assert_eq!(new_checked, old_checked); + } + + #[test] + fn legacy_long_signed_encode_decode() { + let call: TestCall = vec![0u8; 257].into(); + let signed = TEST_ACCOUNT; + let extension = DummyExtension; + let implicit = extension.implicit().unwrap(); + let signature = TestSig( + TEST_ACCOUNT, + blake2_256(&(&call, DummyExtension, &implicit).encode()[..]).to_vec(), + ); + + let old_ux = + UncheckedExtrinsicV4::::new_signed( + call.clone(), + signed, + signature.clone(), + extension.clone(), + ); + + let encoded_old_ux = old_ux.encode(); + let decoded_old_ux = Ex::decode(&mut &encoded_old_ux[..]).unwrap(); + + assert_eq!(decoded_old_ux.function, call); + assert_eq!( + decoded_old_ux.preamble, + Preamble::Signed(signed, signature.clone(), extension.clone()) + ); + + let new_ux = Ex::new_signed(call.clone(), signed, signature.clone(), extension.clone()); + + let new_checked = new_ux.check(&IdentityLookup::::default()).unwrap(); + let old_checked = + decoded_old_ux.check(&IdentityLookup::::default()).unwrap(); + assert_eq!(new_checked, old_checked); + } + + #[test] + fn legacy_unsigned_encode_decode() { + let call: TestCall = vec![0u8; 0].into(); + + let old_ux = + UncheckedExtrinsicV4::::new_unsigned( + call.clone(), + ); + + let encoded_old_ux = old_ux.encode(); + let decoded_old_ux = Ex::decode(&mut &encoded_old_ux[..]).unwrap(); + + assert_eq!(decoded_old_ux.function, call); + assert_eq!(decoded_old_ux.preamble, Preamble::Bare(LEGACY_EXTRINSIC_FORMAT_VERSION)); + + let new_legacy_ux = Ex::new_bare_legacy(call.clone()); + assert_eq!(encoded_old_ux, new_legacy_ux.encode()); + + let new_ux = Ex::new_bare(call.clone()); + let encoded_new_ux = new_ux.encode(); + let decoded_new_ux = Ex::decode(&mut &encoded_new_ux[..]).unwrap(); + assert_eq!(new_ux, decoded_new_ux); + + let new_checked = new_ux.check(&IdentityLookup::::default()).unwrap(); + let old_checked = + decoded_old_ux.check(&IdentityLookup::::default()).unwrap(); + assert_eq!(new_checked, old_checked); } } diff --git a/substrate/primitives/runtime/src/lib.rs b/substrate/primitives/runtime/src/lib.rs index 260c9a91855a..f0c8e50f1ba1 100644 --- a/substrate/primitives/runtime/src/lib.rs +++ b/substrate/primitives/runtime/src/lib.rs @@ -26,7 +26,7 @@ //! communication between the client and the runtime. This includes: //! //! - A set of traits to declare what any block/header/extrinsic type should provide. -//! - [`traits::Block`], [`traits::Header`], [`traits::Extrinsic`] +//! - [`traits::Block`], [`traits::Header`], [`traits::ExtrinsicLike`] //! - A set of types that implement these traits, whilst still providing a high degree of //! configurability via generics. //! - [`generic::Block`], [`generic::Header`], [`generic::UncheckedExtrinsic`] and @@ -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; @@ -131,6 +128,8 @@ pub use sp_arithmetic::{ FixedPointOperand, FixedU128, FixedU64, InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, Rational128, Rounding, UpperOf, }; +/// Re-export this since it's part of the API of this crate. +pub use sp_weights::Weight; pub use either::Either; @@ -951,13 +950,14 @@ 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))) } } -impl traits::Extrinsic for OpaqueExtrinsic { - type Call = (); - type SignaturePayload = (); +impl traits::ExtrinsicLike for OpaqueExtrinsic { + fn is_bare(&self) -> bool { + false + } } /// Print something that implements `Printable` from the runtime. @@ -1034,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/testing.rs b/substrate/primitives/runtime/src/testing.rs index b4aeda5a0e7a..1fc78cce6707 100644 --- a/substrate/primitives/runtime/src/testing.rs +++ b/substrate/primitives/runtime/src/testing.rs @@ -19,26 +19,15 @@ use crate::{ codec::{Codec, Decode, Encode, MaxEncodedLen}, - generic, + generic::{self, UncheckedExtrinsic}, scale_info::TypeInfo, - traits::{ - self, Applyable, BlakeTwo256, Checkable, DispatchInfoOf, Dispatchable, OpaqueKeys, - PostDispatchInfoOf, SignaturePayload, SignedExtension, ValidateUnsigned, - }, - transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, - ApplyExtrinsicResultWithInfo, KeyTypeId, -}; -use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; -use sp_core::{ - crypto::{key_types, ByteArray, CryptoType, Dummy}, - U256, + traits::{self, BlakeTwo256, Dispatchable, OpaqueKeys}, + DispatchResultWithInfo, KeyTypeId, }; +use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize}; +use sp_core::crypto::{key_types, ByteArray, CryptoType, Dummy}; pub use sp_core::{sr25519, H256}; -use std::{ - cell::RefCell, - fmt::{self, Debug}, - ops::Deref, -}; +use std::{cell::RefCell, fmt::Debug}; /// A dummy type which can be used instead of regular cryptographic primitives. /// @@ -79,9 +68,15 @@ impl From for u64 { impl UintAuthorityId { /// Convert this authority ID into a public key. pub fn to_public_key(&self) -> T { - let bytes: [u8; 32] = U256::from(self.0).into(); + let mut bytes = [0u8; 32]; + bytes[0..8].copy_from_slice(&self.0.to_le_bytes()); T::from_slice(&bytes).unwrap() } + + /// Set the list of keys returned by the runtime call for all keys of that type. + pub fn set_all_keys>(keys: impl IntoIterator) { + ALL_KEYS.with(|l| *l.borrow_mut() = keys.into_iter().map(Into::into).collect()) + } } impl CryptoType for UintAuthorityId { @@ -106,13 +101,6 @@ thread_local! { static ALL_KEYS: RefCell> = RefCell::new(vec![]); } -impl UintAuthorityId { - /// Set the list of keys returned by the runtime call for all keys of that type. - pub fn set_all_keys>(keys: impl IntoIterator) { - ALL_KEYS.with(|l| *l.borrow_mut() = keys.into_iter().map(Into::into).collect()) - } -} - impl sp_application_crypto::RuntimeAppPublic for UintAuthorityId { const ID: KeyTypeId = key_types::DUMMY; @@ -164,6 +152,18 @@ impl traits::IdentifyAccount for UintAuthorityId { } } +impl traits::Verify for UintAuthorityId { + type Signer = Self; + + fn verify>( + &self, + _msg: L, + signer: &::AccountId, + ) -> bool { + self.0 == *signer + } +} + /// A dummy signature type, to match `UintAuthorityId`. #[derive(Eq, PartialEq, Clone, Debug, Hash, Serialize, Deserialize, Encode, Decode, TypeInfo)] pub struct TestSignature(pub u64, pub Vec); @@ -198,42 +198,6 @@ impl Header { } } -/// An opaque extrinsic wrapper type. -#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] -pub struct ExtrinsicWrapper(Xt); - -impl traits::Extrinsic for ExtrinsicWrapper { - type Call = (); - type SignaturePayload = (); - - fn is_signed(&self) -> Option { - None - } -} - -impl serde::Serialize for ExtrinsicWrapper { - fn serialize(&self, seq: S) -> Result - where - S: ::serde::Serializer, - { - self.using_encoded(|bytes| seq.serialize_bytes(bytes)) - } -} - -impl From for ExtrinsicWrapper { - fn from(xt: Xt) -> Self { - ExtrinsicWrapper(xt) - } -} - -impl Deref for ExtrinsicWrapper { - type Target = Xt; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - /// Testing block #[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode, TypeInfo)] pub struct Block { @@ -248,7 +212,16 @@ impl traits::HeaderProvider for Block { } impl< - Xt: 'static + Codec + Sized + Send + Sync + Serialize + Clone + Eq + Debug + traits::Extrinsic, + Xt: 'static + + Codec + + Sized + + Send + + Sync + + Serialize + + Clone + + Eq + + Debug + + traits::ExtrinsicLike, > traits::Block for Block { type Extrinsic = Xt; @@ -283,139 +256,25 @@ where } } -/// The signature payload of a `TestXt`. -type TxSignaturePayload = (u64, Extra); +/// Extrinsic type with `u64` accounts and mocked signatures, used in testing. +pub type TestXt = UncheckedExtrinsic; -impl SignaturePayload for TxSignaturePayload { - type SignatureAddress = u64; - type Signature = (); - type SignatureExtra = Extra; -} +/// Wrapper over a `u64` that can be used as a `RuntimeCall`. +#[derive(PartialEq, Eq, Debug, Clone, Encode, Decode, TypeInfo)] +pub struct MockCallU64(pub u64); -/// Test transaction, tuple of (sender, call, signed_extra) -/// with index only used if sender is some. -/// -/// If sender is some then the transaction is signed otherwise it is unsigned. -#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] -pub struct TestXt { - /// Signature of the extrinsic. - pub signature: Option>, - /// Call of the extrinsic. - pub call: Call, -} - -impl TestXt { - /// Create a new `TextXt`. - pub fn new(call: Call, signature: Option<(u64, Extra)>) -> Self { - Self { call, signature } - } -} - -impl Serialize for TestXt -where - TestXt: Encode, -{ - fn serialize(&self, seq: S) -> Result - where - S: Serializer, - { - self.using_encoded(|bytes| seq.serialize_bytes(bytes)) - } -} - -impl Debug for TestXt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TestXt({:?}, ...)", self.signature.as_ref().map(|x| &x.0)) - } -} - -impl Checkable for TestXt { - type Checked = Self; - fn check(self, _: &Context) -> Result { - Ok(self) - } - - #[cfg(feature = "try-runtime")] - fn unchecked_into_checked_i_know_what_i_am_doing( - self, - _: &Context, - ) -> Result { - unreachable!() - } -} - -impl traits::Extrinsic - for TestXt -{ - type Call = Call; - type SignaturePayload = TxSignaturePayload; - - fn is_signed(&self) -> Option { - Some(self.signature.is_some()) - } - - fn new(c: Call, sig: Option) -> Option { - Some(TestXt { signature: sig, call: c }) +impl Dispatchable for MockCallU64 { + type RuntimeOrigin = u64; + type Config = (); + type Info = (); + type PostInfo = (); + fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo { + Ok(()) } } -impl traits::ExtrinsicMetadata for TestXt -where - Call: Codec + Sync + Send, - Extra: SignedExtension, -{ - type SignedExtensions = Extra; - const VERSION: u8 = 0u8; -} - -impl Applyable for TestXt -where - Call: 'static - + Sized - + Send - + Sync - + Clone - + Eq - + Codec - + Debug - + Dispatchable, - Extra: SignedExtension, - Origin: From>, -{ - type Call = Call; - - /// Checks to see if this is a valid *transaction*. It returns information on it if so. - fn validate>( - &self, - source: TransactionSource, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - if let Some((ref id, ref extra)) = self.signature { - Extra::validate(extra, id, &self.call, info, len) - } else { - let valid = Extra::validate_unsigned(&self.call, info, len)?; - let unsigned_validation = U::validate_unsigned(source, &self.call)?; - Ok(valid.combine_with(unsigned_validation)) - } - } - - /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, - /// index and sender. - fn apply>( - self, - info: &DispatchInfoOf, - len: usize, - ) -> ApplyExtrinsicResultWithInfo> { - let maybe_who = if let Some((who, extra)) = self.signature { - Extra::pre_dispatch(extra, &who, &self.call, info, len)?; - Some(who) - } else { - Extra::pre_dispatch_unsigned(&self.call, info, len)?; - U::pre_dispatch(&self.call)?; - None - }; - - Ok(self.call.dispatch(maybe_who.into())) +impl From for MockCallU64 { + fn from(value: u64) -> Self { + Self(value) } } diff --git a/substrate/primitives/runtime/src/traits.rs b/substrate/primitives/runtime/src/traits/mod.rs similarity index 91% rename from substrate/primitives/runtime/src/traits.rs rename to substrate/primitives/runtime/src/traits/mod.rs index fc63bc76decb..01bdcca86b6f 100644 --- a/substrate/primitives/runtime/src/traits.rs +++ b/substrate/primitives/runtime/src/traits/mod.rs @@ -19,7 +19,7 @@ use crate::{ generic::Digest, - scale_info::{MetaType, StaticTypeInfo, TypeInfo}, + scale_info::{StaticTypeInfo, TypeInfo}, transaction_validity::{ TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction, ValidTransaction, @@ -44,14 +44,20 @@ 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; #[cfg(feature = "std")] use std::str::FromStr; +pub mod transaction_extension; +pub use transaction_extension::{ + DispatchTransaction, TransactionExtension, TransactionExtensionMetadata, ValidateResult, +}; + /// A lazy value. pub trait Lazy { /// Get a reference to the underlying value. @@ -226,8 +232,14 @@ pub trait StaticLookup { } /// A lookup implementation returning the input value. -#[derive(Default, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct IdentityLookup(PhantomData); +impl Default for IdentityLookup { + fn default() -> Self { + Self(PhantomData::::default()) + } +} + impl StaticLookup for IdentityLookup { type Source = T; type Target = T; @@ -1253,7 +1265,7 @@ pub trait Header: // that is then used to define `UncheckedExtrinsic`. // ```ignore // pub type UncheckedExtrinsic = -// generic::UncheckedExtrinsic; +// generic::UncheckedExtrinsic; // ``` // This `UncheckedExtrinsic` is supplied to the `Block`. // ```ignore @@ -1286,7 +1298,7 @@ pub trait Block: + 'static { /// Type for extrinsics. - type Extrinsic: Member + Codec + Extrinsic + MaybeSerialize; + type Extrinsic: Member + Codec + ExtrinsicLike + MaybeSerialize; /// Header type. type Header: Header + MaybeSerializeDeserialize; /// Block hash type. @@ -1310,6 +1322,7 @@ pub trait Block: } /// Something that acts like an `Extrinsic`. +#[deprecated = "Use `ExtrinsicLike` along with the `CreateTransaction` trait family instead"] pub trait Extrinsic: Sized { /// The function call. type Call: TypeInfo; @@ -1327,17 +1340,49 @@ pub trait Extrinsic: Sized { None } - /// Create new instance of the extrinsic. - /// - /// Extrinsics can be split into: - /// 1. Inherents (no signature; created by validators during block production) - /// 2. Unsigned Transactions (no signature; represent "system calls" or other special kinds of - /// calls) 3. Signed Transactions (with signature; a regular transactions with known origin) + /// Returns `true` if this `Extrinsic` is bare. + fn is_bare(&self) -> bool { + !self.is_signed().unwrap_or(true) + } + + /// Create a new old-school extrinsic, either a bare extrinsic if `_signed_data` is `None` or + /// a signed transaction is it is `Some`. fn new(_call: Self::Call, _signed_data: Option) -> Option { None } } +/// Something that acts like an `Extrinsic`. +pub trait ExtrinsicLike: Sized { + /// Is this `Extrinsic` signed? + /// If no information are available about signed/unsigned, `None` should be returned. + #[deprecated = "Use and implement `!is_bare()` instead"] + fn is_signed(&self) -> Option { + None + } + + /// Returns `true` if this `Extrinsic` is bare. + fn is_bare(&self) -> bool { + #[allow(deprecated)] + !self.is_signed().unwrap_or(true) + } +} + +#[allow(deprecated)] +impl ExtrinsicLike for T +where + T: Extrinsic, +{ + fn is_signed(&self) -> Option { + #[allow(deprecated)] + ::is_signed(&self) + } + + fn is_bare(&self) -> bool { + ::is_bare(&self) + } +} + /// Something that acts like a [`SignaturePayload`](Extrinsic::SignaturePayload) of an /// [`Extrinsic`]. pub trait SignaturePayload { @@ -1370,8 +1415,8 @@ pub trait ExtrinsicMetadata { /// By format is meant the encoded representation of the `Extrinsic`. const VERSION: u8; - /// Signed extensions attached to this `Extrinsic`. - type SignedExtensions: SignedExtension; + /// Transaction extensions attached to this `Extrinsic`. + type TransactionExtensions; } /// Extract the hashing type for a block. @@ -1435,6 +1480,27 @@ impl Checkable for T { } } +/// A type that can handle weight refunds. +pub trait RefundWeight { + /// Refund some unspent weight. + fn refund(&mut self, weight: sp_weights::Weight); +} + +/// A type that can handle weight refunds and incorporate extension weights into the call weight +/// after dispatch. +pub trait ExtensionPostDispatchWeightHandler: RefundWeight { + /// Accrue some weight pertaining to the extension. + fn set_extension_weight(&mut self, info: &DispatchInfo); +} + +impl RefundWeight for () { + fn refund(&mut self, _weight: sp_weights::Weight) {} +} + +impl ExtensionPostDispatchWeightHandler<()> for () { + fn set_extension_weight(&mut self, _info: &()) {} +} + /// A lazy call (module function and argument values) that can be executed via its `dispatch` /// method. pub trait Dispatchable { @@ -1450,12 +1516,21 @@ pub trait Dispatchable { type Info; /// Additional information that is returned by `dispatch`. Can be used to supply the caller /// with information about a `Dispatchable` that is only known post dispatch. - type PostInfo: Eq + PartialEq + Clone + Copy + Encode + Decode + Printable; + type PostInfo: Eq + + PartialEq + + Clone + + Copy + + Encode + + Decode + + Printable + + ExtensionPostDispatchWeightHandler; /// Actually dispatch this call and return the result of it. fn dispatch(self, origin: Self::RuntimeOrigin) -> crate::DispatchResultWithInfo; } +/// Shortcut to reference the `RuntimeOrigin` type of a `Dispatchable`. +pub type DispatchOriginOf = ::RuntimeOrigin; /// Shortcut to reference the `Info` type of a `Dispatchable`. pub type DispatchInfoOf = ::Info; /// Shortcut to reference the `PostInfo` type of a `Dispatchable`. @@ -1474,8 +1549,75 @@ impl Dispatchable for () { } } +/// Dispatchable impl containing an arbitrary value which panics if it actually is dispatched. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct FakeDispatchable(pub Inner); +impl From for FakeDispatchable { + fn from(inner: Inner) -> Self { + Self(inner) + } +} +impl FakeDispatchable { + /// Take `self` and return the underlying inner value. + pub fn deconstruct(self) -> Inner { + self.0 + } +} +impl AsRef for FakeDispatchable { + fn as_ref(&self) -> &Inner { + &self.0 + } +} + +impl Dispatchable for FakeDispatchable { + type RuntimeOrigin = (); + type Config = (); + type Info = (); + type PostInfo = (); + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { + panic!("This implementation should not be used for actual dispatch."); + } +} + +/// Runtime Origin which includes a System Origin variant whose `AccountId` is the parameter. +pub trait AsSystemOriginSigner { + /// Extract a reference of the inner value of the System `Origin::Signed` variant, if self has + /// that variant. + fn as_system_origin_signer(&self) -> Option<&AccountId>; +} + +/// Interface to differentiate between Runtime Origins authorized to include a transaction into the +/// block and dispatch it, and those who aren't. +/// +/// This trait targets transactions, by which we mean extrinsics which are validated through a +/// [`TransactionExtension`]. This excludes bare extrinsics (i.e. inherents), which have their call, +/// not their origin, validated and authorized. +/// +/// Typically, upon validation or application of a transaction, the origin resulting from the +/// transaction extension (see [`TransactionExtension`]) is checked for authorization. The +/// transaction is then rejected or applied. +/// +/// In FRAME, an authorized origin is either an `Origin::Signed` System origin or a custom origin +/// authorized in a [`TransactionExtension`]. +pub trait AsTransactionAuthorizedOrigin { + /// Whether the origin is authorized to include a transaction in a block. + /// + /// In typical FRAME chains, this function returns `false` if the origin is a System + /// `Origin::None` variant, `true` otherwise, meaning only signed or custom origin resulting + /// from the transaction extension pipeline are authorized. + /// + /// NOTE: This function should not be used in the context of bare extrinsics (i.e. inherents), + /// as bare extrinsics do not authorize the origin but rather the call itself, and are not + /// validated through the [`TransactionExtension`] pipeline. + fn is_transaction_authorized(&self) -> bool; +} + /// Means by which a transaction may be extended. This type embodies both the data and the logic /// that should be additionally associated with the transaction. It should be plain old data. +#[deprecated = "Use `TransactionExtension` instead."] pub trait SignedExtension: Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo { @@ -1493,7 +1635,7 @@ pub trait SignedExtension: /// Any additional data that will go into the signed payload. This may be created dynamically /// from the transaction using the `additional_signed` function. - type AdditionalSigned: Encode + TypeInfo; + type AdditionalSigned: Codec + TypeInfo; /// The type that encodes information that can be passed from pre_dispatch to post-dispatch. type Pre; @@ -1532,38 +1674,6 @@ pub trait SignedExtension: len: usize, ) -> Result; - /// Validate an unsigned transaction for the transaction queue. - /// - /// This function can be called frequently by the transaction queue - /// to obtain transaction validity against current state. - /// It should perform all checks that determine a valid unsigned transaction, - /// and quickly eliminate ones that are stale or incorrect. - /// - /// Make sure to perform the same checks in `pre_dispatch_unsigned` function. - fn validate_unsigned( - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> TransactionValidity { - Ok(ValidTransaction::default()) - } - - /// Do any pre-flight stuff for a unsigned transaction. - /// - /// Note this function by default delegates to `validate_unsigned`, so that - /// all checks performed for the transaction queue are also performed during - /// the dispatch phase (applying the extrinsic). - /// - /// If you ever override this function, you need to make sure to always - /// perform the same validation as in `validate_unsigned`. - fn pre_dispatch_unsigned( - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(), TransactionValidityError> { - Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into) - } - /// Do any post-flight stuff for an extrinsic. /// /// If the transaction is signed, then `_pre` will contain the output of `pre_dispatch`, @@ -1594,125 +1704,46 @@ pub trait SignedExtension: /// /// As a [`SignedExtension`] can be a tuple of [`SignedExtension`]s we need to return a `Vec` /// that holds the metadata of each one. Each individual `SignedExtension` must return - /// *exactly* one [`SignedExtensionMetadata`]. + /// *exactly* one [`TransactionExtensionMetadata`]. /// /// This method provides a default implementation that returns a vec containing a single - /// [`SignedExtensionMetadata`]. - fn metadata() -> Vec { - alloc::vec![SignedExtensionMetadata { + /// [`TransactionExtensionMetadata`]. + fn metadata() -> Vec { + sp_std::vec![TransactionExtensionMetadata { identifier: Self::IDENTIFIER, ty: scale_info::meta_type::(), - additional_signed: scale_info::meta_type::() + implicit: scale_info::meta_type::() }] } -} - -/// Information about a [`SignedExtension`] for the runtime metadata. -pub struct SignedExtensionMetadata { - /// The unique identifier of the [`SignedExtension`]. - pub identifier: &'static str, - /// The type of the [`SignedExtension`]. - pub ty: MetaType, - /// The type of the [`SignedExtension`] additional signed data for the payload. - pub additional_signed: MetaType, -} - -#[impl_for_tuples(1, 12)] -impl SignedExtension for Tuple { - for_tuples!( where #( Tuple: SignedExtension )* ); - type AccountId = AccountId; - type Call = Call; - const IDENTIFIER: &'static str = "You should call `identifier()`!"; - for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); - for_tuples!( type Pre = ( #( Tuple::Pre ),* ); ); - - fn additional_signed(&self) -> Result { - Ok(for_tuples!( ( #( Tuple.additional_signed()? ),* ) )) - } - - fn validate( - &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - let valid = ValidTransaction::default(); - for_tuples!( #( let valid = valid.combine_with(Tuple.validate(who, call, info, len)?); )* ); - Ok(valid) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - Ok(for_tuples!( ( #( Tuple.pre_dispatch(who, call, info, len)? ),* ) )) - } + /// Validate an unsigned transaction for the transaction queue. + /// + /// This function can be called frequently by the transaction queue + /// to obtain transaction validity against current state. + /// It should perform all checks that determine a valid unsigned transaction, + /// and quickly eliminate ones that are stale or incorrect. fn validate_unsigned( - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, ) -> TransactionValidity { - let valid = ValidTransaction::default(); - for_tuples!( #( let valid = valid.combine_with(Tuple::validate_unsigned(call, info, len)?); )* ); - Ok(valid) + Ok(ValidTransaction::default()) } + /// Do any pre-flight stuff for an unsigned transaction. + /// + /// Note this function by default delegates to `validate_unsigned`, so that + /// all checks performed for the transaction queue are also performed during + /// the dispatch phase (applying the extrinsic). + /// + /// If you ever override this function, you need not perform the same validation as in + /// `validate_unsigned`. fn pre_dispatch_unsigned( call: &Self::Call, info: &DispatchInfoOf, len: usize, ) -> Result<(), TransactionValidityError> { - for_tuples!( #( Tuple::pre_dispatch_unsigned(call, info, len)?; )* ); - Ok(()) - } - - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - match pre { - Some(x) => { - for_tuples!( #( Tuple::post_dispatch(Some(x.Tuple), info, post_info, len, result)?; )* ); - }, - None => { - for_tuples!( #( Tuple::post_dispatch(None, info, post_info, len, result)?; )* ); - }, - } - Ok(()) - } - - fn metadata() -> Vec { - let mut ids = Vec::new(); - for_tuples!( #( ids.extend(Tuple::metadata()); )* ); - ids - } -} - -impl SignedExtension for () { - type AccountId = u64; - type AdditionalSigned = (); - type Call = (); - type Pre = (); - const IDENTIFIER: &'static str = "UnitSignedExtension"; - fn additional_signed(&self) -> core::result::Result<(), TransactionValidityError> { - Ok(()) - } - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + Self::validate_unsigned(call, info, len).map(|_| ()).map_err(Into::into) } } @@ -1722,11 +1753,23 @@ impl SignedExtension for () { /// /// Also provides information on to whom this information is attributable and an index that allows /// each piece of attributable information to be disambiguated. +/// +/// IMPORTANT: After validation, in both [validate](Applyable::validate) and +/// [apply](Applyable::apply), all transactions should have *some* authorized origin, except for +/// inherents. This is necessary in order to protect the chain against spam. If no extension in the +/// transaction extension pipeline authorized the transaction with an origin, either a system signed +/// origin or a custom origin, then the transaction must be rejected, as the extensions provided in +/// substrate which protect the chain, such as `CheckNonce`, `ChargeTransactionPayment` etc., rely +/// on the assumption that the system handles system signed transactions, and the pallets handle the +/// custom origin that they authorized. pub trait Applyable: Sized + Send + Sync { /// Type by which we can dispatch. Restricts the `UnsignedValidator` type. type Call: Dispatchable; /// Checks to see if this is a valid *transaction*. It returns information on it if so. + /// + /// IMPORTANT: Ensure that *some* origin has been authorized after validating the transaction. + /// If no origin was authorized, the transaction must be rejected. fn validate>( &self, source: TransactionSource, @@ -1736,6 +1779,9 @@ pub trait Applyable: Sized + Send + Sync { /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. + /// + /// IMPORTANT: Ensure that *some* origin has been authorized after validating the + /// transaction. If no origin was authorized, the transaction must be rejected. fn apply>( self, info: &DispatchInfoOf, 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 new file mode 100644 index 000000000000..282064078fe3 --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/as_transaction_extension.rs @@ -0,0 +1,131 @@ +// 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. + +//! The [AsTransactionExtension] adapter struct for adapting [SignedExtension]s to +//! [TransactionExtension]s. + +#![allow(deprecated)] + +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; + +use crate::{ + traits::{AsSystemOriginSigner, SignedExtension, ValidateResult}, + transaction_validity::{InvalidTransaction, TransactionSource}, +}; + +use super::*; + +/// Adapter to use a `SignedExtension` in the place of a `TransactionExtension`. +#[derive(TypeInfo, Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] +#[deprecated = "Convert your SignedExtension to a TransactionExtension."] +pub struct AsTransactionExtension(pub SE); + +impl Default for AsTransactionExtension { + fn default() -> Self { + Self(SE::default()) + } +} + +impl From for AsTransactionExtension { + fn from(value: SE) -> Self { + Self(value) + } +} + +impl TransactionExtension for AsTransactionExtension +where + ::RuntimeOrigin: AsSystemOriginSigner + Clone, +{ + const IDENTIFIER: &'static str = SE::IDENTIFIER; + type Implicit = SE::AdditionalSigned; + + fn implicit(&self) -> Result { + self.0.additional_signed() + } + fn metadata() -> Vec { + SE::metadata() + } + fn weight(&self, _call: &SE::Call) -> Weight { + Weight::zero() + } + type Val = (); + type Pre = SE::Pre; + + fn validate( + &self, + origin: ::RuntimeOrigin, + call: &SE::Call, + info: &DispatchInfoOf, + 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)?; + Ok((r, (), origin)) + } + + fn prepare( + self, + _: (), + origin: &::RuntimeOrigin, + call: &SE::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + self.0.pre_dispatch(who, call, info, len) + } + + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result { + SE::post_dispatch(Some(pre), info, post_info, len, result)?; + Ok(Weight::zero()) + } + + fn bare_validate( + call: &SE::Call, + info: &DispatchInfoOf, + len: usize, + ) -> TransactionValidity { + SE::validate_unsigned(call, info, len) + } + + fn bare_validate_and_prepare( + call: &SE::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + SE::pre_dispatch_unsigned(call, info, len) + } + + fn bare_post_dispatch( + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + SE::post_dispatch(None, info, post_info, len, result) + } +} diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs new file mode 100644 index 000000000000..28030d12fc9f --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/dispatch_transaction.rs @@ -0,0 +1,185 @@ +// 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. + +//! The [DispatchTransaction] trait. + +use crate::{ + generic::ExtensionVersion, + traits::AsTransactionAuthorizedOrigin, + transaction_validity::{InvalidTransaction, TransactionSource}, +}; + +use super::*; + +/// Single-function utility trait with a blanket impl over [`TransactionExtension`] in order to +/// provide transaction dispatching functionality. We avoid implementing this directly on the trait +/// since we never want it to be overriden by the trait implementation. +pub trait DispatchTransaction { + /// The origin type of the transaction. + type Origin; + /// The info type. + type Info; + /// The resultant type. + type Result; + /// The `Val` of the extension. + type Val; + /// The `Pre` of the extension. + type Pre; + /// Just validate a transaction. + /// + /// The is basically the same as [validate](TransactionExtension::validate), except that there + /// is no need to supply the bond data. + fn validate_only( + &self, + origin: Self::Origin, + 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( + self, + origin: Self::Origin, + 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( + self, + origin: Self::Origin, + 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 + /// dispatch the call, it doesn't need to consume it and so `call` can be passed as a reference. + fn test_run( + self, + origin: Self::Origin, + call: &Call, + info: &Self::Info, + len: usize, + extension_version: ExtensionVersion, + substitute: impl FnOnce( + Self::Origin, + ) -> crate::DispatchResultWithInfo<::PostInfo>, + ) -> Self::Result; +} + +impl, Call: Dispatchable + Encode> DispatchTransaction for T +where + ::RuntimeOrigin: AsTransactionAuthorizedOrigin, +{ + type Origin = ::RuntimeOrigin; + type Info = DispatchInfoOf; + type Result = crate::ApplyExtrinsicResultWithInfo>; + type Val = T::Val; + type Pre = T::Pre; + + fn validate_only( + &self, + origin: Self::Origin, + 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()?, + &(extension_version, call), + source, + ) { + // After validation, some origin must have been authorized. + Ok((_, _, origin)) if !origin.is_transaction_authorized() => + Err(InvalidTransaction::UnknownOrigin.into()), + res => res, + } + } + fn validate_and_prepare( + self, + origin: Self::Origin, + 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, + TransactionSource::InBlock, + extension_version, + )?; + let pre = self.prepare(val, &origin, &call, info, len)?; + Ok((pre, origin)) + } + fn dispatch_transaction( + self, + origin: ::RuntimeOrigin, + call: Call, + info: &DispatchInfoOf, + len: usize, + extension_version: ExtensionVersion, + ) -> Self::Result { + 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 { + Ok(info) => info, + Err(err) => &mut err.post_info, + }; + post_info.set_extension_weight(info); + T::post_dispatch(pre, info, post_info, len, &pd_res)?; + Ok(res) + } + fn test_run( + self, + origin: Self::Origin, + 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, extension_version)?; + let mut res = substitute(origin); + let pd_res = res.map(|_| ()).map_err(|e| e.error); + let post_info = match &mut res { + Ok(info) => info, + Err(err) => &mut err.post_info, + }; + post_info.set_extension_weight(info); + T::post_dispatch(pre, info, post_info, len, &pd_res)?; + Ok(res) + } +} diff --git a/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs new file mode 100644 index 000000000000..f8c5dc6a724e --- /dev/null +++ b/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs @@ -0,0 +1,641 @@ +// 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. + +//! The transaction extension trait. + +use crate::{ + scale_info::{MetaType, StaticTypeInfo}, + transaction_validity::{ + TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, + }, + DispatchResult, +}; +use codec::{Codec, Decode, Encode}; +use impl_trait_for_tuples::impl_for_tuples; +#[doc(hidden)] +pub use sp_std::marker::PhantomData; +use sp_std::{self, fmt::Debug, prelude::*}; +use sp_weights::Weight; +use tuplex::{PopFront, PushBack}; + +use super::{ + DispatchInfoOf, DispatchOriginOf, Dispatchable, ExtensionPostDispatchWeightHandler, + PostDispatchInfoOf, RefundWeight, +}; + +mod as_transaction_extension; +mod dispatch_transaction; +#[allow(deprecated)] +pub use as_transaction_extension::AsTransactionExtension; +pub use dispatch_transaction::DispatchTransaction; + +/// Shortcut for the result value of the `validate` function. +pub type ValidateResult = + Result<(ValidTransaction, Val, DispatchOriginOf), TransactionValidityError>; + +/// Means by which a transaction may be extended. This type embodies both the data and the logic +/// that should be additionally associated with the transaction. It should be plain old data. +/// +/// The simplest transaction extension would be the Unit type (and empty pipeline) `()`. This +/// executes no additional logic and implies a dispatch of the transaction's call using the +/// inherited origin (either `None` or `Signed`, depending on whether this is a signed or general +/// transaction). +/// +/// Transaction extensions are capable of altering certain associated semantics: +/// +/// - They may define the origin with which the transaction's call should be dispatched. +/// - They may define various parameters used by the transaction queue to determine under what +/// conditions the transaction should be retained and introduced on-chain. +/// - They may define whether this transaction is acceptable for introduction on-chain at all. +/// +/// Each of these semantics are defined by the `validate` function. +/// +/// **NOTE: Transaction extensions cannot under any circumstances alter the call itself.** +/// +/// Transaction extensions are capable of defining logic which is executed additionally to the +/// dispatch of the call: +/// +/// - They may define logic which must be executed prior to the dispatch of the call. +/// - They may also define logic which must be executed after the dispatch of the call. +/// +/// Each of these semantics are defined by the `prepare` and `post_dispatch_details` functions +/// respectively. +/// +/// Finally, transaction extensions may define additional data to help define the implications of +/// the logic they introduce. This additional data may be explicitly defined by the transaction +/// author (in which case it is included as part of the transaction body), or it may be implicitly +/// defined by the transaction extension based around the on-chain state (which the transaction +/// author is assumed to know). This data may be utilized by the above logic to alter how a node's +/// transaction queue treats this transaction. +/// +/// ## Default implementations +/// +/// Of the 6 functions in this trait along with `TransactionExtension`, 2 of them must return a +/// value of an associated type on success, with only `implicit` having a default implementation. +/// This means that default implementations cannot be provided for `validate` and `prepare`. +/// However, a macro is provided [impl_tx_ext_default](crate::impl_tx_ext_default) which is capable +/// of generating default implementations for both of these functions. If you do not wish to +/// introduce additional logic into the transaction pipeline, then it is recommended that you use +/// this macro to implement these functions. Additionally, [weight](TransactionExtension::weight) +/// can return a default value, which would mean the extension is weightless, but it is not +/// implemented by default. Instead, implementers can explicitly choose to implement this default +/// behavior through the same [impl_tx_ext_default](crate::impl_tx_ext_default) macro. +/// +/// If your extension does any post-flight logic, then the functionality must be implemented in +/// [post_dispatch_details](TransactionExtension::post_dispatch_details). This function can return +/// the actual weight used by the extension during an entire dispatch cycle by wrapping said weight +/// value in a `Some`. This is useful in computing fee refunds, similar to how post dispatch +/// information is used to refund fees for calls. Alternatively, a `None` can be returned, which +/// means that the worst case scenario weight, namely the value returned by +/// [weight](TransactionExtension::weight), is the actual weight. This particular piece of logic +/// is embedded in the default implementation of +/// [post_dispatch](TransactionExtension::post_dispatch) so that the weight is assumed to be worst +/// case scenario, but implementers of this trait can correct it with extra effort. Therefore, all +/// users of an extension should use [post_dispatch](TransactionExtension::post_dispatch), with +/// [post_dispatch_details](TransactionExtension::post_dispatch_details) considered an internal +/// function. +/// +/// ## Pipelines, Inherited Implications, and Authorized Origins +/// +/// Requiring a single transaction extension to define all of the above semantics would be +/// cumbersome and would lead to a lot of boilerplate. Instead, transaction extensions are +/// aggregated into pipelines, which are tuples of transaction extensions. Each extension in the +/// pipeline is executed in order, and the output of each extension is aggregated and/or relayed as +/// the input to the next extension in the pipeline. +/// +/// This ordered composition happens with all data types ([Val](TransactionExtension::Val), +/// [Pre](TransactionExtension::Pre) and [Implicit](TransactionExtension::Implicit)) as well as +/// all functions. There are important consequences stemming from how the composition affects the +/// meaning of the `origin` and `implication` parameters as well as the results. Whereas the +/// [prepare](TransactionExtension::prepare) and +/// [post_dispatch](TransactionExtension::post_dispatch) functions are clear in their meaning, the +/// [validate](TransactionExtension::validate) function is fairly sophisticated and warrants further +/// explanation. +/// +/// Firstly, the `origin` parameter. The `origin` passed into the first item in a pipeline is simply +/// that passed into the tuple itself. It represents an authority who has authorized the implication +/// of the transaction, as of the extension it has been passed into *and any further extensions it +/// may pass though, all the way to, and including, the transaction's dispatch call itself. Each +/// following item in the pipeline is passed the origin which the previous item returned. The origin +/// returned from the final item in the pipeline is the origin which is returned by the tuple +/// itself. +/// +/// This means that if a constituent extension returns a different origin to the one it was called +/// with, then (assuming no other extension changes it further) *this new origin will be used for +/// all extensions following it in the pipeline, and will be returned from the pipeline to be used +/// as the origin for the call's dispatch*. The call itself as well as all these extensions +/// following may each imply consequence for this origin. We call this the *inherited implication*. +/// +/// The *inherited implication* is the cumulated on-chain effects born by whatever origin is +/// returned. It is expressed to the [validate](TransactionExtension::validate) function only as the +/// `implication` argument which implements the [Encode] trait. A transaction extension may define +/// its own implications through its own fields and the +/// [implicit](TransactionExtension::implicit) function. This is only utilized by extensions +/// which precede it in a pipeline or, if the transaction is an old-school signed transaction, the +/// underlying transaction verification logic. +/// +/// **The inherited implication passed as the `implication` parameter to +/// [validate](TransactionExtension::validate) does not include the extension's inner data itself +/// nor does it include the result of the extension's `implicit` function.** If you both provide an +/// implication and rely on the implication, then you need to manually aggregate your extensions +/// implication with the aggregated implication passed in. +/// +/// In the post dispatch pipeline, the actual weight of each extension is accrued in the +/// [PostDispatchInfo](PostDispatchInfoOf) of that transaction sequentially with each +/// [post_dispatch](TransactionExtension::post_dispatch) call. This means that an extension handling +/// transaction payment and refunds should be at the end of the pipeline in order to capture the +/// correct amount of weight used during the call. This is because one cannot know the actual weight +/// of an extension after post dispatch without running the post dispatch ahead of time. +pub trait TransactionExtension: + Codec + Debug + Sync + Send + Clone + Eq + PartialEq + StaticTypeInfo +{ + /// Unique identifier of this signed extension. + /// + /// This will be exposed in the metadata to identify the signed extension used in an extrinsic. + const IDENTIFIER: &'static str; + + /// Any additional data which was known at the time of transaction construction and can be + /// useful in authenticating the transaction. This is determined dynamically in part from the + /// on-chain environment using the `implicit` function and not directly contained in the + /// transaction itself and therefore is considered "implicit". + type Implicit: Codec + StaticTypeInfo; + + /// Determine any additional data which was known at the time of transaction construction and + /// can be useful in authenticating the transaction. The expected usage of this is to include in + /// any data which is signed and verified as part of transaction validation. Also perform any + /// pre-signature-verification checks and return an error if needed. + fn implicit(&self) -> Result { + use crate::transaction_validity::InvalidTransaction::IndeterminateImplicit; + Ok(Self::Implicit::decode(&mut &[][..]).map_err(|_| IndeterminateImplicit)?) + } + + /// Returns the metadata for this extension. + /// + /// As a [`TransactionExtension`] can be a tuple of [`TransactionExtension`]s we need to return + /// a `Vec` that holds the metadata of each one. Each individual `TransactionExtension` must + /// return *exactly* one [`TransactionExtensionMetadata`]. + /// + /// This method provides a default implementation that returns a vec containing a single + /// [`TransactionExtensionMetadata`]. + fn metadata() -> Vec { + sp_std::vec![TransactionExtensionMetadata { + identifier: Self::IDENTIFIER, + ty: scale_info::meta_type::(), + implicit: scale_info::meta_type::() + }] + } + + /// The type that encodes information that can be passed from `validate` to `prepare`. + type Val; + + /// The type that encodes information that can be passed from `prepare` to `post_dispatch`. + type Pre; + + /// The weight consumed by executing this extension instance fully during transaction dispatch. + fn weight(&self, call: &Call) -> Weight; + + /// Validate a transaction for the transaction queue. + /// + /// This function can be called frequently by the transaction queue to obtain transaction + /// validity against current state. It should perform all checks that determine a valid + /// transaction, that can pay for its execution and quickly eliminate ones that are stale or + /// incorrect. + /// + /// Parameters: + /// - `origin`: The origin of the transaction which this extension inherited; coming from an + /// "old-school" *signed transaction*, this will be a system `RawOrigin::Signed` value. If the + /// transaction is a "new-school" *General Transaction*, then this will be a system + /// `RawOrigin::None` value. If this extension is an item in a composite, then it could be + /// anything which was previously returned as an `origin` value in the result of a `validate` + /// call. + /// - `call`: The `Call` wrapped by this extension. + /// - `info`: Information concerning, and inherent to, the transaction's call. + /// - `len`: The total length of the encoded transaction. + /// - `inherited_implication`: The *implication* which this extension inherits. This is a tuple + /// of the transaction's call and some additional opaque-but-encodable data. Coming directly + /// from a transaction, the latter is [()]. However, if this extension is expressed as part of + /// a composite type, then the latter component is equal to any further implications to which + /// the returned `origin` could potentially apply. See Pipelines, Inherited Implications, and + /// Authorized Origins for more information. + /// + /// Returns a [ValidateResult], which is a [Result] whose success type is a tuple of + /// [ValidTransaction] (defining useful metadata for the transaction queue), the [Self::Val] + /// token of this transaction, which gets passed into [prepare](TransactionExtension::prepare), + /// and the origin of the transaction, which gets passed into + /// [prepare](TransactionExtension::prepare) and is ultimately used for dispatch. + fn validate( + &self, + origin: DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + self_implicit: Self::Implicit, + inherited_implication: &impl Encode, + source: TransactionSource, + ) -> ValidateResult; + + /// Do any pre-flight stuff for a transaction after validation. + /// + /// This is for actions which do not happen in the transaction queue but only immediately prior + /// to the point of dispatch on-chain. This should not return an error, since errors should + /// already have been identified during the [validate](TransactionExtension::validate) call. If + /// an error is returned, the transaction will be considered invalid but no state changes will + /// happen and therefore work done in [validate](TransactionExtension::validate) will not be + /// paid for. + /// + /// Unlike `validate`, this function may consume `self`. + /// + /// Parameters: + /// - `val`: `Self::Val` returned by the result of the `validate` call. + /// - `origin`: The origin returned by the result of the `validate` call. + /// - `call`: The `Call` wrapped by this extension. + /// - `info`: Information concerning, and inherent to, the transaction's call. + /// - `len`: The total length of the encoded transaction. + /// + /// Returns a [Self::Pre] value on success, which gets passed into + /// [post_dispatch](TransactionExtension::post_dispatch) and after the call is dispatched. + /// + /// IMPORTANT: **Checks made in validation need not be repeated here.** + fn prepare( + self, + val: Self::Val, + origin: &DispatchOriginOf, + call: &Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result; + + /// Do any post-flight stuff for an extrinsic. + /// + /// `_pre` contains the output of `prepare`. + /// + /// This gets given the `DispatchResult` `_result` from the extrinsic and can, if desired, + /// introduce a `TransactionValidityError`, causing the block to become invalid for including + /// it. + /// + /// On success, the caller must return the amount of unspent weight left over by this extension + /// after dispatch. By default, this function returns no unspent weight, which means the entire + /// weight computed for the worst case scenario is consumed. + /// + /// WARNING: This function does not automatically keep track of accumulated "actual" weight. + /// Unless this weight is handled at the call site, use + /// [post_dispatch](TransactionExtension::post_dispatch) + /// instead. + /// + /// Parameters: + /// - `pre`: `Self::Pre` returned by the result of the `prepare` call prior to dispatch. + /// - `info`: Information concerning, and inherent to, the transaction's call. + /// - `post_info`: Information concerning the dispatch of the transaction's call. + /// - `len`: The total length of the encoded transaction. + /// - `result`: The result of the dispatch. + /// + /// WARNING: It is dangerous to return an error here. To do so will fundamentally invalidate the + /// transaction and any block that it is included in, causing the block author to not be + /// compensated for their work in validating the transaction or producing the block so far. It + /// can only be used safely when you *know* that the transaction is one that would only be + /// introduced by the current block author. + fn post_dispatch_details( + _pre: Self::Pre, + _info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result { + Ok(Weight::zero()) + } + + /// A wrapper for [`post_dispatch_details`](TransactionExtension::post_dispatch_details) that + /// refunds the unspent weight consumed by this extension into the post dispatch information. + /// + /// If `post_dispatch_details` returns a non-zero unspent weight, which, by definition, must be + /// less than the worst case weight provided by [weight](TransactionExtension::weight), that + /// is the value refunded in `post_info`. + /// + /// If no unspent weight is reported by `post_dispatch_details`, this function assumes the worst + /// case weight and does not refund anything. + /// + /// For more information, look into + /// [post_dispatch_details](TransactionExtension::post_dispatch_details). + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + let unspent_weight = Self::post_dispatch_details(pre, info, &post_info, len, result)?; + post_info.refund(unspent_weight); + + Ok(()) + } + + /// Validation logic for bare extrinsics. + /// + /// NOTE: This function will be migrated to a separate `InherentExtension` interface. + fn bare_validate( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + Ok(ValidTransaction::default()) + } + + /// All pre-flight logic run before dispatching bare extrinsics. + /// + /// NOTE: This function will be migrated to a separate `InherentExtension` interface. + fn bare_validate_and_prepare( + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } + + /// Post dispatch logic run after dispatching bare extrinsics. + /// + /// NOTE: This function will be migrated to a separate `InherentExtension` interface. + fn bare_post_dispatch( + _info: &DispatchInfoOf, + _post_info: &mut PostDispatchInfoOf, + _len: usize, + _result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } +} + +/// Helper macro to be used in a `impl TransactionExtension` block to add default implementations of +/// `weight`, `validate`, `prepare` or any combinations of the them. +/// +/// The macro is to be used with 2 parameters, separated by ";": +/// - the `Call` type; +/// - the functions for which a default implementation should be generated, separated by " "; +/// available options are `weight`, `validate` and `prepare`. +/// +/// Example usage: +/// ```nocompile +/// impl TransactionExtension for EmptyExtension { +/// type Val = (); +/// type Pre = (); +/// +/// impl_tx_ext_default!(FirstCall; weight validate prepare); +/// } +/// +/// impl TransactionExtension for SimpleExtension { +/// type Val = u32; +/// type Pre = (); +/// +/// fn weight(&self, _: &SecondCall) -> Weight { +/// Weight::zero() +/// } +/// +/// fn validate( +/// &self, +/// _origin: ::RuntimeOrigin, +/// _call: &SecondCall, +/// _info: &DispatchInfoOf, +/// _len: usize, +/// _self_implicit: Self::Implicit, +/// _inherited_implication: &impl Encode, +/// ) -> ValidateResult { +/// Ok((Default::default(), 42u32, origin)) +/// } +/// +/// impl_tx_ext_default!(SecondCall; prepare); +/// } +/// ``` +#[macro_export] +macro_rules! impl_tx_ext_default { + ($call:ty ; , $( $rest:tt )*) => { + impl_tx_ext_default!{$call ; $( $rest )*} + }; + ($call:ty ; validate $( $rest:tt )*) => { + fn validate( + &self, + origin: $crate::traits::DispatchOriginOf<$call>, + _call: &$call, + _info: &$crate::traits::DispatchInfoOf<$call>, + _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)) + } + impl_tx_ext_default!{$call ; $( $rest )*} + }; + ($call:ty ; prepare $( $rest:tt )*) => { + fn prepare( + self, + _val: Self::Val, + _origin: &$crate::traits::DispatchOriginOf<$call>, + _call: &$call, + _info: &$crate::traits::DispatchInfoOf<$call>, + _len: usize, + ) -> Result { + Ok(Default::default()) + } + impl_tx_ext_default!{$call ; $( $rest )*} + }; + ($call:ty ; weight $( $rest:tt )*) => { + fn weight(&self, _call: &$call) -> $crate::Weight { + $crate::Weight::zero() + } + impl_tx_ext_default!{$call ; $( $rest )*} + }; + ($call:ty ;) => {}; +} + +/// Information about a [`TransactionExtension`] for the runtime metadata. +pub struct TransactionExtensionMetadata { + /// The unique identifier of the [`TransactionExtension`]. + pub identifier: &'static str, + /// The type of the [`TransactionExtension`]. + pub ty: MetaType, + /// The type of the [`TransactionExtension`] additional signed data for the payload. + pub implicit: MetaType, +} + +#[impl_for_tuples(1, 12)] +impl TransactionExtension for Tuple { + const IDENTIFIER: &'static str = "Use `metadata()`!"; + for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); + fn implicit(&self) -> Result { + Ok(for_tuples!( ( #( Tuple.implicit()? ),* ) )) + } + fn metadata() -> Vec { + let mut ids = Vec::new(); + for_tuples!( #( ids.extend(Tuple::metadata()); )* ); + ids + } + + for_tuples!( type Val = ( #( Tuple::Val ),* ); ); + for_tuples!( type Pre = ( #( Tuple::Pre ),* ); ); + + fn weight(&self, call: &Call) -> Weight { + let mut weight = Weight::zero(); + for_tuples!( #( weight = weight.saturating_add(Tuple.weight(call)); )* ); + weight + } + + fn validate( + &self, + origin: ::RuntimeOrigin, + call: &Call, + info: &DispatchInfoOf, + len: usize, + self_implicit: Self::Implicit, + inherited_implication: &impl Encode, + source: TransactionSource, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + let valid = ValidTransaction::default(); + let val = (); + let following_explicit_implications = for_tuples!( ( #( &self.Tuple ),* ) ); + let following_implicit_implications = self_implicit; + + for_tuples!(#( + // Implication of this pipeline element not relevant for later items, so we pop it. + let (_item, following_explicit_implications) = following_explicit_implications.pop_front(); + let (item_implicit, following_implicit_implications) = following_implicit_implications.pop_front(); + let (item_valid, item_val, origin) = { + let implications = ( + // The first is the implications born of the fact we return the mutated + // origin. + inherited_implication, + // This is the explicitly made implication born of the fact the new origin is + // passed into the next items in this pipeline-tuple. + &following_explicit_implications, + // This is the implicitly made implication born of the fact the new origin is + // passed into the next items in this pipeline-tuple. + &following_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); + )* ); + Ok((valid, val, origin)) + } + + fn prepare( + self, + val: Self::Val, + origin: &::RuntimeOrigin, + call: &Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + Ok(for_tuples!( ( #( + Tuple::prepare(self.Tuple, val.Tuple, origin, call, info, len)? + ),* ) )) + } + + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result { + let mut total_unspent_weight = Weight::zero(); + for_tuples!( #({ + let unspent_weight = Tuple::post_dispatch_details(pre.Tuple, info, post_info, len, result)?; + total_unspent_weight = total_unspent_weight.saturating_add(unspent_weight); + })* ); + Ok(total_unspent_weight) + } + + fn post_dispatch( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + for_tuples!( #( Tuple::post_dispatch(pre.Tuple, info, post_info, len, result)?; )* ); + Ok(()) + } + + fn bare_validate(call: &Call, info: &DispatchInfoOf, len: usize) -> TransactionValidity { + let valid = ValidTransaction::default(); + for_tuples!(#( + let item_valid = Tuple::bare_validate(call, info, len)?; + let valid = valid.combine_with(item_valid); + )* ); + Ok(valid) + } + + fn bare_validate_and_prepare( + call: &Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result<(), TransactionValidityError> { + for_tuples!( #( Tuple::bare_validate_and_prepare(call, info, len)?; )* ); + Ok(()) + } + + fn bare_post_dispatch( + info: &DispatchInfoOf, + post_info: &mut PostDispatchInfoOf, + len: usize, + result: &DispatchResult, + ) -> Result<(), TransactionValidityError> { + for_tuples!( #( Tuple::bare_post_dispatch(info, post_info, len, result)?; )* ); + Ok(()) + } +} + +impl TransactionExtension for () { + const IDENTIFIER: &'static str = "UnitTransactionExtension"; + type Implicit = (); + fn implicit(&self) -> sp_std::result::Result { + Ok(()) + } + type Val = (); + type Pre = (); + fn weight(&self, _call: &Call) -> Weight { + Weight::zero() + } + fn validate( + &self, + origin: ::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, (), ::RuntimeOrigin), + TransactionValidityError, + > { + Ok((ValidTransaction::default(), (), origin)) + } + fn prepare( + self, + _val: (), + _origin: &::RuntimeOrigin, + _call: &Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result<(), TransactionValidityError> { + Ok(()) + } +} diff --git a/substrate/primitives/runtime/src/transaction_validity.rs b/substrate/primitives/runtime/src/transaction_validity.rs index ffff94e17461..a48c8ee7ba84 100644 --- a/substrate/primitives/runtime/src/transaction_validity.rs +++ b/substrate/primitives/runtime/src/transaction_validity.rs @@ -82,6 +82,10 @@ pub enum InvalidTransaction { MandatoryValidation, /// The sending address is disabled or known to be invalid. BadSigner, + /// The implicit data was unable to be calculated. + IndeterminateImplicit, + /// The transaction extension did not authorize any origin. + UnknownOrigin, } impl InvalidTransaction { @@ -113,6 +117,10 @@ impl From for &'static str { "Transaction dispatch is mandatory; transactions must not be validated.", InvalidTransaction::Custom(_) => "InvalidTransaction custom error", InvalidTransaction::BadSigner => "Invalid signing address", + InvalidTransaction::IndeterminateImplicit => + "The implicit data was unable to be calculated", + InvalidTransaction::UnknownOrigin => + "The transaction extension did not authorize any origin", } } } @@ -226,7 +234,7 @@ impl From for TransactionValidity { /// Depending on the source we might apply different validation schemes. /// For instance we can disallow specific kinds of transactions if they were not produced /// by our local node (for instance off-chain workers). -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, Hash)] pub enum TransactionSource { /// Transaction is already included in block. /// @@ -338,7 +346,7 @@ pub struct ValidTransactionBuilder { impl ValidTransactionBuilder { /// Set the priority of a transaction. /// - /// Note that the final priority for `FRAME` is combined from all `SignedExtension`s. + /// Note that the final priority for `FRAME` is combined from all `TransactionExtension`s. /// Most likely for unsigned transactions you want the priority to be higher /// than for regular transactions. We recommend exposing a base priority for unsigned /// transactions as a runtime module parameter, so that the runtime can tune inter-module diff --git a/substrate/primitives/runtime/src/type_with_default.rs b/substrate/primitives/runtime/src/type_with_default.rs index 1465393640dc..5790e3ab6bf6 100644 --- a/substrate/primitives/runtime/src/type_with_default.rs +++ b/substrate/primitives/runtime/src/type_with_default.rs @@ -91,24 +91,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 +187,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 +507,63 @@ impl> CompactAs for TypeWithDefault { Ok(Self::new(val)) } } + +#[cfg(test)] +mod tests { + use super::TypeWithDefault; + 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 {} + } +} diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 5e94524816a0..17010a8907fc 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -619,7 +619,7 @@ pub trait DelegationMigrator { /// /// Also removed from [`StakingUnchecked`] as a Virtual Staker. Useful for testing. #[cfg(feature = "runtime-benchmarks")] - fn migrate_to_direct_staker(agent: Agent); + fn force_kill_agent(agent: Agent); } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); 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/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/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index 9341d7ac77e2..e441ddae52ef 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -25,12 +25,7 @@ sp-debug-derive = { workspace = true } [features] default = ["std"] -std = [ - "codec/std", - "impl-serde/std", - "serde/std", - "sp-debug-derive/std", -] +std = ["codec/std", "impl-serde/std", "serde/std", "sp-debug-derive/std"] # Serde support without relying on std features. serde = ["dep:serde", "impl-serde"] diff --git a/substrate/primitives/test-primitives/src/lib.rs b/substrate/primitives/test-primitives/src/lib.rs index 1e3b912eaf48..adc96d773694 100644 --- a/substrate/primitives/test-primitives/src/lib.rs +++ b/substrate/primitives/test-primitives/src/lib.rs @@ -28,7 +28,7 @@ use sp_application_crypto::sr25519; use alloc::vec::Vec; pub use sp_core::{hash::H256, RuntimeDebug}; -use sp_runtime::traits::{BlakeTwo256, Extrinsic as ExtrinsicT, Verify}; +use sp_runtime::traits::{BlakeTwo256, ExtrinsicLike, Verify}; /// Extrinsic for test-runtime. #[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] @@ -47,10 +47,7 @@ impl serde::Serialize for Extrinsic { } } -impl ExtrinsicT for Extrinsic { - type Call = Extrinsic; - type SignaturePayload = (); - +impl ExtrinsicLike for Extrinsic { fn is_signed(&self) -> Option { if let Extrinsic::IncludeData(_) = *self { Some(false) @@ -59,8 +56,12 @@ impl ExtrinsicT for Extrinsic { } } - fn new(call: Self::Call, _signature_payload: Option) -> Option { - Some(call) + fn is_bare(&self) -> bool { + if let Extrinsic::IncludeData(_) = *self { + true + } else { + false + } } } 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/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/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index 9b830403dbe8..c4e1897dbb8e 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -47,6 +47,4 @@ serde = [ "sp-arithmetic/serde", ] -json-schema = [ - "dep:schemars", -] +json-schema = ["dep:schemars"] diff --git a/substrate/scripts/run_all_benchmarks.sh b/substrate/scripts/run_all_benchmarks.sh index 6dd7cede319f..053c230fedb4 100755 --- a/substrate/scripts/run_all_benchmarks.sh +++ b/substrate/scripts/run_all_benchmarks.sh @@ -107,6 +107,29 @@ for PALLET in "${PALLETS[@]}"; do FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')"; WEIGHT_FILE="./frame/${FOLDER}/src/weights.rs" + + TEMPLATE_FILE_NAME="frame-weight-template.hbs" + if [ $(cargo metadata --locked --format-version 1 --no-deps | jq --arg pallet "${PALLET//_/-}" -r '.packages[] | select(.name == $pallet) | .dependencies | any(.name == "polkadot-sdk-frame")') = true ] + then + TEMPLATE_FILE_NAME="frame-umbrella-weight-template.hbs" + fi + TEMPLATE_FILE="./.maintain/${TEMPLATE_FILE_NAME}" + + # Special handling of custom weight paths. + if [ "$PALLET" == "frame_system_extensions" ] || [ "$PALLET" == "frame-system-extensions" ] + then + WEIGHT_FILE="./frame/system/src/extensions/weights.rs" + elif [ "$PALLET" == "pallet_asset_conversion_tx_payment" ] || [ "$PALLET" == "pallet-asset-conversion-tx-payment" ] + then + WEIGHT_FILE="./frame/transaction-payment/asset-conversion-tx-payment/src/weights.rs" + elif [ "$PALLET" == "pallet_asset_tx_payment" ] || [ "$PALLET" == "pallet-asset-tx-payment" ] + then + WEIGHT_FILE="./frame/transaction-payment/asset-tx-payment/src/weights.rs" + elif [ "$PALLET" == "pallet_asset_conversion_ops" ] || [ "$PALLET" == "pallet-asset-conversion-ops" ] + then + WEIGHT_FILE="./frame/asset-conversion/ops/src/weights.rs" + fi + echo "[+] Benchmarking $PALLET with weight file $WEIGHT_FILE"; OUTPUT=$( @@ -120,7 +143,7 @@ for PALLET in "${PALLETS[@]}"; do --heap-pages=4096 \ --output="$WEIGHT_FILE" \ --header="./HEADER-APACHE2" \ - --template=./.maintain/frame-weight-template.hbs 2>&1 + --template="$TEMPLATE_FILE" 2>&1 ) if [ $? -ne 0 ]; then echo "$OUTPUT" >> "$ERR_FILE" @@ -160,4 +183,4 @@ if [ -f "$ERR_FILE" ]; then else echo "[+] All benchmarks passed." exit 0 -fi +fi \ No newline at end of file diff --git a/substrate/test-utils/runtime/src/extrinsic.rs b/substrate/test-utils/runtime/src/extrinsic.rs index 5ae0d8f8f6ec..4c884d4174ff 100644 --- a/substrate/test-utils/runtime/src/extrinsic.rs +++ b/substrate/test-utils/runtime/src/extrinsic.rs @@ -26,7 +26,10 @@ use frame_metadata_hash_extension::CheckMetadataHash; use frame_system::{CheckNonce, CheckWeight}; use sp_core::crypto::Pair as TraitPair; use sp_keyring::AccountKeyring; -use sp_runtime::{traits::SignedExtension, transaction_validity::TransactionPriority, Perbill}; +use sp_runtime::{ + generic::Preamble, traits::TransactionExtension, transaction_validity::TransactionPriority, + Perbill, +}; /// Transfer used in test substrate pallet. Extrinsic is created and signed using this data. #[derive(Clone)] @@ -66,11 +69,11 @@ impl TryFrom<&Extrinsic> for TransferData { match uxt { Extrinsic { function: RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest, value }), - signature: Some((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 }), - signature: None, + preamble: Preamble::Bare(_), } => Ok(transfer.clone()), _ => Err(()), } @@ -203,9 +206,8 @@ impl ExtrinsicBuilder { /// Build `Extrinsic` using embedded parameters pub fn build(self) -> Extrinsic { if let Some(signer) = self.signer { - let extra = ( - CheckNonce::from(self.nonce.unwrap_or(0)), - CheckWeight::new(), + let tx_ext = ( + (CheckNonce::from(self.nonce.unwrap_or(0)), CheckWeight::new()), CheckSubstrateCall {}, self.metadata_hash .map(CheckMetadataHash::new_with_custom_hash) @@ -213,14 +215,14 @@ impl ExtrinsicBuilder { ); let raw_payload = SignedPayload::from_raw( self.function.clone(), - extra.clone(), - extra.additional_signed().unwrap(), + tx_ext.clone(), + tx_ext.implicit().unwrap(), ); let signature = raw_payload.using_encoded(|e| signer.sign(e)); - Extrinsic::new_signed(self.function, signer.public(), signature, extra) + Extrinsic::new_signed(self.function, signer.public(), signature, tx_ext) } else { - Extrinsic::new_unsigned(self.function) + Extrinsic::new_bare(self.function) } } } diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 74965264c034..461d583b5cc6 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -63,9 +63,11 @@ 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, - traits::{BlakeTwo256, Block as BlockT, DispatchInfoOf, NumberFor, Verify}, - transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, + impl_opaque_keys, impl_tx_ext_default, + traits::{BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, NumberFor, Verify}, + transaction_validity::{ + TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction, + }, ApplyExtrinsicResult, ExtrinsicInclusionMode, Perbill, }; #[cfg(any(feature = "std", test))] @@ -112,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, @@ -147,18 +149,18 @@ pub type Signature = sr25519::Signature; #[cfg(feature = "std")] pub type Pair = sp_core::sr25519::Pair; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( - CheckNonce, - CheckWeight, +// TODO: Remove after the Checks are migrated to TxExtension. +/// The extension to the basic transaction logic. +pub type TxExtension = ( + (CheckNonce, CheckWeight), CheckSubstrateCall, frame_metadata_hash_extension::CheckMetadataHash, ); /// The payload being signed in transactions. -pub type SignedPayload = sp_runtime::generic::SignedPayload; +pub type SignedPayload = sp_runtime::generic::SignedPayload; /// Unchecked extrinsic type as expected by this runtime. pub type Extrinsic = - sp_runtime::generic::UncheckedExtrinsic; + sp_runtime::generic::UncheckedExtrinsic; /// An identifier for an account on this system. pub type AccountId = ::Signer; @@ -252,8 +254,17 @@ impl sp_runtime::traits::Printable for CheckSubstrateCall { } } +impl sp_runtime::traits::RefundWeight for CheckSubstrateCall { + fn refund(&mut self, _weight: frame_support::weights::Weight) {} +} +impl sp_runtime::traits::ExtensionPostDispatchWeightHandler + for CheckSubstrateCall +{ + fn set_extension_weight(&mut self, _info: &CheckSubstrateCall) {} +} + impl sp_runtime::traits::Dispatchable for CheckSubstrateCall { - type RuntimeOrigin = CheckSubstrateCall; + type RuntimeOrigin = RuntimeOrigin; type Config = CheckSubstrateCall; type Info = CheckSubstrateCall; type PostInfo = CheckSubstrateCall; @@ -266,42 +277,33 @@ impl sp_runtime::traits::Dispatchable for CheckSubstrateCall { } } -impl sp_runtime::traits::SignedExtension for CheckSubstrateCall { - type AccountId = AccountId; - type Call = RuntimeCall; - type AdditionalSigned = (); - type Pre = (); +impl sp_runtime::traits::TransactionExtension for CheckSubstrateCall { const IDENTIFIER: &'static str = "CheckSubstrateCall"; - - fn additional_signed( - &self, - ) -> core::result::Result { - Ok(()) - } + type Implicit = (); + type Pre = (); + type Val = (); + impl_tx_ext_default!(RuntimeCall; weight prepare); fn validate( &self, - _who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + _source: TransactionSource, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { log::trace!(target: LOG_TARGET, "validate"); - match call { + let v = match call { RuntimeCall::SubstrateTest(ref substrate_test_call) => - substrate_test_pallet::validate_runtime_call(substrate_test_call), - _ => Ok(Default::default()), - } - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &sp_runtime::traits::DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(drop) + substrate_test_pallet::validate_runtime_call(substrate_test_call)?, + _ => Default::default(), + }; + Ok((v, (), origin)) } } @@ -670,7 +672,7 @@ impl_runtime_apis! { impl sp_offchain::OffchainWorkerApi for Runtime { fn offchain_worker(header: &::Header) { - let ext = Extrinsic::new_unsigned( + let ext = Extrinsic::new_bare( substrate_test_pallet::pallet::Call::storage_change{ key:b"some_key".encode(), value:Some(header.number.encode()) @@ -726,8 +728,8 @@ 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(), @@ -745,7 +747,7 @@ impl_runtime_apis! { } }) }, - Ok("foobar") => json!({"foo":"bar"}), + "foobar" => json!({"foo":"bar"}), _ => return None, }; Some(serde_json::to_string(&patch) @@ -1051,8 +1053,8 @@ mod tests { use sp_consensus::BlockOrigin; use sp_core::{storage::well_known_keys::HEAP_PAGES, traits::CallContext}; use sp_runtime::{ - traits::{Hash as _, SignedExtension}, - transaction_validity::{InvalidTransaction, ValidTransaction}, + traits::{DispatchTransaction, Hash as _}, + transaction_validity::{InvalidTransaction, TransactionSource::External, ValidTransaction}, }; use substrate_test_runtime_client::{ prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, @@ -1205,26 +1207,32 @@ mod tests { let len = 0_usize; assert_eq!( CheckSubstrateCall {} - .validate( - &x, + .validate_only( + Some(x).into(), &ExtrinsicBuilder::new_call_with_priority(16).build().function, &info, - len + len, + External, + 0, ) .unwrap() + .0 .priority, 16 ); assert_eq!( CheckSubstrateCall {} - .validate( - &x, + .validate_only( + Some(x).into(), &ExtrinsicBuilder::new_call_do_not_propagate().build().function, &info, - len + len, + External, + 0, ) .unwrap() + .0 .propagate, false ); @@ -1389,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] @@ -1403,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] @@ -1416,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()) ); } diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index b5dc034fed13..3cdaea642263 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -17,6 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] 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 } diff --git a/substrate/test-utils/runtime/transaction-pool/src/lib.rs b/substrate/test-utils/runtime/transaction-pool/src/lib.rs index 5202e6e65154..6a4f38f63e82 100644 --- a/substrate/test-utils/runtime/transaction-pool/src/lib.rs +++ b/substrate/test-utils/runtime/transaction-pool/src/lib.rs @@ -23,7 +23,7 @@ use codec::Encode; use futures::future::ready; use parking_lot::RwLock; use sc_transaction_pool::ChainApi; -use sp_blockchain::{CachedHeaderMetadata, TreeRoute}; +use sp_blockchain::{CachedHeaderMetadata, HashAndNumber, TreeRoute}; use sp_runtime::{ generic::{self, BlockId}, traits::{ @@ -34,7 +34,10 @@ use sp_runtime::{ ValidTransaction, }, }; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + sync::Arc, +}; use substrate_test_runtime_client::{ runtime::{ AccountId, Block, BlockNumber, Extrinsic, ExtrinsicBuilder, Hash, Header, Nonce, Transfer, @@ -46,7 +49,7 @@ use substrate_test_runtime_client::{ /// Error type used by [`TestApi`]. #[derive(Debug, thiserror::Error)] #[error(transparent)] -pub struct Error(#[from] sc_transaction_pool_api::error::Error); +pub struct Error(#[from] pub sc_transaction_pool_api::error::Error); impl sc_transaction_pool_api::error::IntoPoolError for Error { fn into_pool_error(self) -> Result { @@ -79,7 +82,7 @@ impl From for IsBestBlock { pub struct ChainState { pub block_by_number: BTreeMap>, pub block_by_hash: HashMap, - pub nonces: HashMap, + pub nonces: HashMap>, pub invalid_hashes: HashSet, pub priorities: HashMap, } @@ -89,14 +92,22 @@ pub struct TestApi { valid_modifier: RwLock>, chain: RwLock, validation_requests: RwLock>, + enable_stale_check: bool, } impl TestApi { /// Test Api with Alice nonce set initially. pub fn with_alice_nonce(nonce: u64) -> Self { let api = Self::empty(); + assert_eq!(api.chain.read().block_by_hash.len(), 1); + assert_eq!(api.chain.read().nonces.len(), 1); - api.chain.write().nonces.insert(Alice.into(), nonce); + api.chain + .write() + .nonces + .values_mut() + .nth(0) + .map(|h| h.insert(Alice.into(), nonce)); api } @@ -107,14 +118,23 @@ impl TestApi { valid_modifier: RwLock::new(Box::new(|_| {})), chain: Default::default(), validation_requests: RwLock::new(Default::default()), + enable_stale_check: false, }; // Push genesis block api.push_block(0, Vec::new(), true); + let hash0 = *api.chain.read().block_by_hash.keys().nth(0).unwrap(); + api.chain.write().nonces.insert(hash0, Default::default()); + api } + pub fn enable_stale_check(mut self) -> Self { + self.enable_stale_check = true; + self + } + /// Set hook on modify valid result of transaction. pub fn set_valid_modifier(&self, modifier: Box) { *self.valid_modifier.write() = modifier; @@ -184,6 +204,24 @@ impl TestApi { let mut chain = self.chain.write(); chain.block_by_hash.insert(hash, block.clone()); + if *block_number > 0 { + // copy nonces to new block + let prev_nonces = chain + .nonces + .get(block.header.parent_hash()) + .expect("there shall be nonces for parent block") + .clone(); + chain.nonces.insert(hash, prev_nonces); + } + + log::info!( + "add_block: {:?} {:?} {:?} nonces:{:#?}", + block_number, + hash, + block.header.parent_hash(), + chain.nonces + ); + if is_best_block { chain .block_by_number @@ -241,10 +279,33 @@ impl TestApi { &self.chain } + /// Set nonce in the inner state for given block. + pub fn set_nonce(&self, at: Hash, account: AccountId, nonce: u64) { + let mut chain = self.chain.write(); + chain.nonces.entry(at).and_modify(|h| { + h.insert(account, nonce); + }); + + log::debug!("set_nonce: {:?} nonces:{:#?}", at, chain.nonces); + } + + /// Increment nonce in the inner state for given block. + pub fn increment_nonce_at_block(&self, at: Hash, account: AccountId) { + let mut chain = self.chain.write(); + chain.nonces.entry(at).and_modify(|h| { + h.entry(account).and_modify(|n| *n += 1).or_insert(1); + }); + + log::debug!("increment_nonce_at_block: {:?} nonces:{:#?}", at, chain.nonces); + } + /// Increment nonce in the inner state. pub fn increment_nonce(&self, account: AccountId) { let mut chain = self.chain.write(); - chain.nonces.entry(account).and_modify(|n| *n += 1).or_insert(1); + // if no particular block was given, then update nonce everywhere + chain.nonces.values_mut().for_each(|h| { + h.entry(account).and_modify(|n| *n += 1).or_insert(1); + }) } /// Calculate a tree route between the two given blocks. @@ -260,6 +321,26 @@ impl TestApi { pub fn expect_hash_from_number(&self, n: BlockNumber) -> Hash { self.block_id_to_hash(&BlockId::Number(n)).unwrap().unwrap() } + + /// Helper function for getting genesis hash + pub fn genesis_hash(&self) -> Hash { + self.expect_hash_from_number(0) + } + + pub fn expect_hash_and_number(&self, n: BlockNumber) -> HashAndNumber { + HashAndNumber { hash: self.expect_hash_from_number(n), number: n } + } +} + +trait TagFrom { + fn tag_from(&self) -> u8; +} + +impl TagFrom for AccountId { + fn tag_from(&self) -> u8 { + let f = AccountKeyring::iter().enumerate().find(|k| AccountId::from(k.1) == *self); + u8::try_from(f.unwrap().0).unwrap() + } } impl ChainApi for TestApi { @@ -272,9 +353,11 @@ impl ChainApi for TestApi { &self, at: ::Hash, _source: TransactionSource, - uxt: ::Extrinsic, + uxt: Arc<::Extrinsic>, ) -> Self::ValidationFuture { + let uxt = (*uxt).clone(); self.validation_requests.write().push(uxt.clone()); + let block_number; match self.block_id_to_number(&BlockId::Hash(at)) { Ok(Some(number)) => { @@ -285,6 +368,7 @@ impl ChainApi for TestApi { .get(&number) .map(|blocks| blocks.iter().any(|b| b.1.is_best())) .unwrap_or(false); + block_number = Some(number); // If there is no best block, we don't know based on which block we should validate // the transaction. (This is not required for this test function, but in real @@ -303,10 +387,44 @@ impl ChainApi for TestApi { } let (requires, provides) = if let Ok(transfer) = TransferData::try_from(&uxt) { - let chain_nonce = self.chain.read().nonces.get(&transfer.from).cloned().unwrap_or(0); - let requires = - if chain_nonce == transfer.nonce { vec![] } else { vec![vec![chain_nonce as u8]] }; - let provides = vec![vec![transfer.nonce as u8]]; + let chain_nonce = self + .chain + .read() + .nonces + .get(&at) + .expect("nonces must be there for every block") + .get(&transfer.from) + .cloned() + .unwrap_or(0); + let requires = if chain_nonce == transfer.nonce { + vec![] + } else { + if self.enable_stale_check { + vec![vec![transfer.from.tag_from(), (transfer.nonce - 1) as u8]] + } else { + vec![vec![(transfer.nonce - 1) as u8]] + } + }; + let provides = if self.enable_stale_check { + vec![vec![transfer.from.tag_from(), transfer.nonce as u8]] + } else { + vec![vec![transfer.nonce as u8]] + }; + + log::info!( + "test_api::validate_transaction: h:{:?} n:{:?} cn:{:?} tn:{:?} r:{:?} p:{:?}", + at, + block_number, + chain_nonce, + transfer.nonce, + requires, + provides, + ); + + if self.enable_stale_check && transfer.nonce < chain_nonce { + log::info!("test_api::validate_transaction: invalid_transaction(stale)...."); + return ready(Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)))) + } (requires, provides) } else { @@ -314,6 +432,7 @@ impl ChainApi for TestApi { }; if self.chain.read().invalid_hashes.contains(&self.hash_and_length(&uxt).0) { + log::info!("test_api::validate_transaction: invalid_transaction...."); return ready(Ok(Err(TransactionValidityError::Invalid(InvalidTransaction::Custom(0))))) } @@ -331,6 +450,15 @@ impl ChainApi for TestApi { ready(Ok(Ok(validity))) } + fn validate_transaction_blocking( + &self, + _at: ::Hash, + _source: TransactionSource, + _uxt: Arc<::Extrinsic>, + ) -> Result { + unimplemented!(); + } + fn block_id_to_number( &self, at: &BlockId, diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index ee5522f5bc04..8a4a06b1b40a 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -41,6 +41,7 @@ sc-cli = { workspace = true } 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-service = { workspace = true } sc-sysinfo = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } @@ -51,13 +52,30 @@ sp-externalities = { workspace = true, default-features = true } sp-genesis-builder = { workspace = true, default-features = true } sp-inherents = { 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-transaction-pool = { 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 } + +[dev-dependencies] +cumulus-test-runtime = { workspace = true, default-features = true } +substrate-test-runtime = { workspace = true, default-features = true } +westend-runtime = { workspace = true, default-features = true } [features] default = ["rocksdb"] @@ -65,8 +83,11 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "westend-runtime/runtime-benchmarks", ] rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index f0a7436dc729..0693db0dbbdd 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -17,7 +17,7 @@ //! Contains the core benchmarking logic. -use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder}; +use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder, BuiltBlock}; use sc_cli::{Error, Result}; use sc_client_api::UsageProvider; use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; @@ -31,14 +31,15 @@ use sp_runtime::{ Digest, DigestItem, OpaqueExtrinsic, }; +use super::ExtrinsicBuilder; +use crate::shared::{StatSelect, Stats}; use clap::Args; +use codec::Encode; use log::info; use serde::Serialize; +use sp_trie::proof_size_extension::ProofSizeExt; use std::{marker::PhantomData, sync::Arc, time::Instant}; -use super::ExtrinsicBuilder; -use crate::shared::{StatSelect, Stats}; - /// Parameters to configure an *overhead* benchmark. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { @@ -66,6 +67,7 @@ pub(crate) struct Benchmark { params: BenchmarkParams, inherent_data: sp_inherents::InherentData, digest_items: Vec, + record_proof: bool, _p: PhantomData, } @@ -84,15 +86,19 @@ where params: BenchmarkParams, inherent_data: sp_inherents::InherentData, digest_items: Vec, + record_proof: bool, ) -> Self { - Self { client, params, inherent_data, digest_items, _p: PhantomData } + Self { client, params, inherent_data, digest_items, record_proof, _p: PhantomData } } /// Benchmark a block with only inherents. - pub fn bench_block(&self) -> Result { - let (block, _) = self.build_block(None)?; + /// + /// Returns the Ref time stats and the proof size. + pub fn bench_block(&self) -> Result<(Stats, u64)> { + let (block, _, proof_size) = self.build_block(None)?; let record = self.measure_block(&block)?; - Stats::new(&record) + + Ok((Stats::new(&record)?, proof_size)) } /// Benchmark the time of an extrinsic in a full block. @@ -100,13 +106,14 @@ where /// First benchmarks an empty block, analogous to `bench_block` and use it as baseline. /// Then benchmarks a full block built with the given `ext_builder` and subtracts the baseline /// from the result. - /// This is necessary to account for the time the inherents use. - pub fn bench_extrinsic(&self, ext_builder: &dyn ExtrinsicBuilder) -> Result { - let (block, _) = self.build_block(None)?; + /// This is necessary to account for the time the inherents use. Returns ref time stats and the + /// proof size. + pub fn bench_extrinsic(&self, ext_builder: &dyn ExtrinsicBuilder) -> Result<(Stats, u64)> { + let (block, _, base_proof_size) = self.build_block(None)?; let base = self.measure_block(&block)?; let base_time = Stats::new(&base)?.select(StatSelect::Average); - let (block, num_ext) = self.build_block(Some(ext_builder))?; + let (block, num_ext, proof_size) = self.build_block(Some(ext_builder))?; let num_ext = num_ext.ok_or_else(|| Error::Input("Block was empty".into()))?; let mut records = self.measure_block(&block)?; @@ -117,23 +124,24 @@ where *r = ((*r as f64) / (num_ext as f64)).ceil() as u64; } - Stats::new(&records) + Ok((Stats::new(&records)?, proof_size.saturating_sub(base_proof_size))) } /// Builds a block with some optional extrinsics. /// /// Returns the block and the number of extrinsics in the block - /// that are not inherents. + /// that are not inherents together with the proof size. /// Returns a block with only inherents if `ext_builder` is `None`. fn build_block( &self, ext_builder: Option<&dyn ExtrinsicBuilder>, - ) -> Result<(Block, Option)> { + ) -> Result<(Block, Option, u64)> { let chain = self.client.usage_info().chain; let mut builder = BlockBuilderBuilder::new(&*self.client) .on_parent_block(chain.best_hash) .with_parent_block_number(chain.best_number) .with_inherent_digests(Digest { logs: self.digest_items.clone() }) + .with_proof_recording(self.record_proof) .build()?; // Create and insert the inherents. @@ -142,34 +150,42 @@ where builder.push(inherent)?; } - // Return early if `ext_builder` is `None`. - let ext_builder = if let Some(ext_builder) = ext_builder { - ext_builder - } else { - return Ok((builder.build()?.block, None)) + let num_ext = match ext_builder { + Some(ext_builder) => { + // Put as many extrinsics into the block as possible and count them. + info!("Building block, this takes some time..."); + let mut num_ext = 0; + for nonce in 0..self.max_ext_per_block() { + let ext = ext_builder.build(nonce)?; + match builder.push(ext.clone()) { + Ok(()) => {}, + Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( + InvalidTransaction::ExhaustsResources, + )))) => break, // Block is full + Err(e) => return Err(Error::Client(e)), + } + num_ext += 1; + } + if num_ext == 0 { + return Err("A Block must hold at least one extrinsic".into()) + } + info!("Extrinsics per block: {}", num_ext); + Some(num_ext) + }, + None => None, }; - // Put as many extrinsics into the block as possible and count them. - info!("Building block, this takes some time..."); - let mut num_ext = 0; - for nonce in 0..self.max_ext_per_block() { - let ext = ext_builder.build(nonce)?; - match builder.push(ext.clone()) { - Ok(()) => {}, - Err(ApplyExtrinsicFailed(Validity(TransactionValidityError::Invalid( - InvalidTransaction::ExhaustsResources, - )))) => break, // Block is full - Err(e) => return Err(Error::Client(e)), - } - num_ext += 1; - } - if num_ext == 0 { - return Err("A Block must hold at least one extrinsic".into()) - } - info!("Extrinsics per block: {}", num_ext); - let block = builder.build()?.block; - - Ok((block, Some(num_ext))) + let BuiltBlock { block, proof, .. } = builder.build()?; + + Ok(( + block, + num_ext, + proof + .map(|p| p.encoded_size()) + .unwrap_or(0) + .try_into() + .map_err(|_| "Proof size is too large".to_string())?, + )) } /// Measures the time that it take to execute a block or an extrinsic. @@ -177,27 +193,35 @@ where let mut record = BenchRecord::new(); let genesis = self.client.info().genesis_hash; + let measure_block = || -> Result { + let block = block.clone(); + let mut runtime_api = self.client.runtime_api(); + if self.record_proof { + 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 start = Instant::now(); + + runtime_api + .execute_block(genesis, block) + .map_err(|e| Error::Client(RuntimeApiError(e)))?; + + Ok(start.elapsed().as_nanos()) + }; + info!("Running {} warmups...", self.params.warmup); for _ in 0..self.params.warmup { - self.client - .runtime_api() - .execute_block(genesis, block.clone()) - .map_err(|e| Error::Client(RuntimeApiError(e)))?; + let _ = measure_block()?; } info!("Executing block {} times", self.params.repeat); // Interesting part here: // Execute a block multiple times and record each execution time. for _ in 0..self.params.repeat { - let block = block.clone(); - let runtime_api = self.client.runtime_api(); - let start = Instant::now(); - - runtime_api - .execute_block(genesis, block) - .map_err(|e| Error::Client(RuntimeApiError(e)))?; - - let elapsed = start.elapsed().as_nanos(); + let elapsed = measure_block()?; record.push(elapsed as u64); } diff --git a/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 99c0230617cb..949b8211556a 100644 --- a/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/substrate/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -118,7 +118,8 @@ impl ExtrinsicCmd { return Err("Unknown pallet or extrinsic. Use --list for a complete list.".into()), }; - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); + let bench = + Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items, false); let stats = bench.bench_extrinsic(ext_builder)?; info!( "Executing a {}::{} extrinsic takes[ns]:\n{:?}", diff --git a/substrate/utils/frame/benchmarking-cli/src/lib.rs b/substrate/utils/frame/benchmarking-cli/src/lib.rs index 0ef2c299de63..1e8642e54d70 100644 --- a/substrate/utils/frame/benchmarking-cli/src/lib.rs +++ b/substrate/utils/frame/benchmarking-cli/src/lib.rs @@ -28,7 +28,11 @@ mod storage; pub use block::BlockCmd; pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE}; -pub use overhead::OverheadCmd; +pub use overhead::{ + remark_builder::{DynamicRemarkBuilder, SubstrateRemarkBuilder}, + runtime_utilities::fetch_latest_metadata_from_code_blob, + OpaqueBlock, OverheadCmd, +}; pub use pallet::PalletCmd; pub use sc_service::BasePath; pub use storage::StorageCmd; diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs deleted file mode 100644 index 4fa8cecf2f7d..000000000000 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ /dev/null @@ -1,175 +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. - -//! Contains the [`OverheadCmd`] as entry point for the CLI to execute -//! the *overhead* benchmarks. - -use sc_block_builder::BlockBuilderApi; -use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; -use sc_client_api::UsageProvider; -use sc_service::Configuration; -use sp_api::{ApiExt, CallApiAt, ProvideRuntimeApi}; -use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; - -use clap::{Args, Parser}; -use log::info; -use serde::Serialize; -use std::{fmt::Debug, path::PathBuf, sync::Arc}; - -use crate::{ - extrinsic::{ - bench::{Benchmark, BenchmarkParams as ExtrinsicBenchmarkParams}, - ExtrinsicBuilder, - }, - overhead::template::TemplateData, - shared::{HostInfoParams, WeightParams}, -}; - -/// Benchmark the execution overhead per-block and per-extrinsic. -#[derive(Debug, Parser)] -pub struct OverheadCmd { - #[allow(missing_docs)] - #[clap(flatten)] - pub shared_params: SharedParams, - - #[allow(missing_docs)] - #[clap(flatten)] - pub import_params: ImportParams, - - #[allow(missing_docs)] - #[clap(flatten)] - pub params: OverheadParams, -} - -/// Configures the benchmark, the post-processing and weight generation. -#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] -pub struct OverheadParams { - #[allow(missing_docs)] - #[clap(flatten)] - pub weight: WeightParams, - - #[allow(missing_docs)] - #[clap(flatten)] - pub bench: ExtrinsicBenchmarkParams, - - #[allow(missing_docs)] - #[clap(flatten)] - pub hostinfo: HostInfoParams, - - /// Add a header to the generated weight output file. - /// - /// Good for adding LICENSE headers. - #[arg(long, value_name = "PATH")] - pub header: Option, - - /// Enable the Trie cache. - /// - /// This should only be used for performance analysis and not for final results. - #[arg(long)] - pub enable_trie_cache: bool, -} - -/// Type of a benchmark. -#[derive(Serialize, Clone, PartialEq, Copy)] -pub(crate) enum BenchmarkType { - /// Measure the per-extrinsic execution overhead. - Extrinsic, - /// Measure the per-block execution overhead. - Block, -} - -impl OverheadCmd { - /// Measure the per-block and per-extrinsic execution overhead. - /// - /// Writes the results to console and into two instances of the - /// `weights.hbs` template, one for each benchmark. - pub fn run( - &self, - cfg: Configuration, - client: Arc, - inherent_data: sp_inherents::InherentData, - digest_items: Vec, - ext_builder: &dyn ExtrinsicBuilder, - ) -> Result<()> - where - Block: BlockT, - C: ProvideRuntimeApi - + CallApiAt - + UsageProvider - + sp_blockchain::HeaderBackend, - C::Api: ApiExt + BlockBuilderApi, - { - if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { - return Err(format!("The extrinsic builder is required to build `System::Remark` extrinsics but builds `{}` extrinsics instead", ext_builder.name()).into()); - } - let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); - - // per-block execution overhead - { - let stats = bench.bench_block()?; - info!("Per-block execution overhead [ns]:\n{:?}", stats); - let template = TemplateData::new(BenchmarkType::Block, &cfg, &self.params, &stats)?; - template.write(&self.params.weight.weight_path)?; - } - // per-extrinsic execution overhead - { - let stats = bench.bench_extrinsic(ext_builder)?; - info!("Per-extrinsic execution overhead [ns]:\n{:?}", stats); - let template = TemplateData::new(BenchmarkType::Extrinsic, &cfg, &self.params, &stats)?; - template.write(&self.params.weight.weight_path)?; - } - - Ok(()) - } -} - -impl BenchmarkType { - /// Short name of the benchmark type. - pub(crate) fn short_name(&self) -> &'static str { - match self { - Self::Extrinsic => "extrinsic", - Self::Block => "block", - } - } - - /// Long name of the benchmark type. - pub(crate) fn long_name(&self) -> &'static str { - match self { - Self::Extrinsic => "ExtrinsicBase", - Self::Block => "BlockExecution", - } - } -} - -// Boilerplate -impl CliConfiguration for OverheadCmd { - fn shared_params(&self) -> &SharedParams { - &self.shared_params - } - - fn import_params(&self) -> Option<&ImportParams> { - Some(&self.import_params) - } - - fn trie_cache_maximum_size(&self) -> Result> { - if self.params.enable_trie_cache { - Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) - } else { - Ok(None) - } - } -} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs new file mode 100644 index 000000000000..8102f14b4f4b --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/command.rs @@ -0,0 +1,774 @@ +// 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. + +//! 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}, + ExtrinsicBuilder, + }, + overhead::{ + command::ChainType::{Parachain, Relaychain, Unknown}, + fake_runtime_api, + remark_builder::SubstrateRemarkBuilder, + template::TemplateData, + }, + shared::{ + genesis_state, + genesis_state::{GenesisStateHandler, SpecGenesisSource}, + HostInfoParams, WeightParams, + }, +}; +use clap::{error::ErrorKind, Args, CommandFactory, Parser}; +use codec::Encode; +use cumulus_client_parachain_inherent::MockValidationDataInherentDataProvider; +use fake_runtime_api::RuntimeApi as FakeRuntimeApi; +use frame_support::Deserialize; +use genesis_state::WARN_SPEC_GENESIS_CTOR; +use log::info; +use polkadot_parachain_primitives::primitives::Id as ParaId; +use sc_block_builder::BlockBuilderApi; +use sc_chain_spec::{ChainSpec, ChainSpecExtension, GenesisBlockBuilder}; +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_service::{new_client, new_db_backend, BasePath, ClientConfig, TFullClient, TaskManager}; +use serde::Serialize; +use serde_json::{json, Value}; +use sp_api::{ApiExt, CallApiAt, Core, ProvideRuntimeApi}; +use sp_blockchain::HeaderBackend; +use sp_core::H256; +use sp_inherents::{InherentData, InherentDataProvider}; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, Block as BlockT}, + DigestItem, OpaqueExtrinsic, +}; +use sp_storage::Storage; +use sp_wasm_interface::HostFunctions; +use std::{ + fmt::{Debug, Display, Formatter}, + fs, + path::PathBuf, + sync::Arc, +}; +use subxt::{client::RuntimeVersion, ext::futures, Metadata}; + +const DEFAULT_PARA_ID: u32 = 100; +const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::overhead"; + +/// Benchmark the execution overhead per-block and per-extrinsic. +#[derive(Debug, Parser)] +pub struct OverheadCmd { + #[allow(missing_docs)] + #[clap(flatten)] + pub shared_params: SharedParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub import_params: ImportParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub params: OverheadParams, +} + +/// Configures the benchmark, the post-processing and weight generation. +#[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] +pub struct OverheadParams { + #[allow(missing_docs)] + #[clap(flatten)] + pub weight: WeightParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub bench: ExtrinsicBenchmarkParams, + + #[allow(missing_docs)] + #[clap(flatten)] + pub hostinfo: HostInfoParams, + + /// Add a header to the generated weight output file. + /// + /// Good for adding LICENSE headers. + #[arg(long, value_name = "PATH")] + pub header: Option, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[arg(long)] + pub enable_trie_cache: bool, + + /// Optional runtime blob to use instead of the one from the genesis config. + #[arg( + long, + value_name = "PATH", + conflicts_with = "chain", + required_if_eq("genesis_builder", "runtime") + )] + pub runtime: Option, + + /// The preset that we expect to find in the GenesisBuilder runtime API. + /// + /// This can be useful when a runtime has a dedicated benchmarking preset instead of using the + /// default one. + #[arg(long, default_value = sp_genesis_builder::DEV_RUNTIME_PRESET)] + pub genesis_builder_preset: String, + + /// How to construct the genesis state. + /// + /// Can be used together with `--chain` to determine whether the + /// genesis state should be initialized with the values from the + /// provided chain spec or a runtime-provided genesis preset. + #[arg(long, value_enum, alias = "genesis-builder-policy")] + pub genesis_builder: Option, + + /// Parachain Id to use for parachains. If not specified, the benchmark code will choose + /// a para-id and patch the state accordingly. + #[arg(long)] + pub para_id: Option, +} + +/// How the genesis state for benchmarking should be built. +#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] +#[clap(rename_all = "kebab-case")] +pub enum GenesisBuilderPolicy { + /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. + /// This will use the `development` preset by default. + Runtime, + /// Use the runtime from the Spec file to build the genesis state. + SpecRuntime, + /// Use the spec file to build the genesis state. This fails when there is no spec. + #[value(alias = "spec")] + SpecGenesis, +} + +/// Type of a benchmark. +#[derive(Serialize, Clone, PartialEq, Copy)] +pub(crate) enum BenchmarkType { + /// Measure the per-extrinsic execution overhead. + Extrinsic, + /// Measure the per-block execution overhead. + Block, +} + +/// Hostfunctions that are typically used by parachains. +pub type ParachainHostFunctions = ( + cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions, + sp_io::SubstrateHostFunctions, +); + +pub type BlockNumber = u32; + +/// Typical block header. +pub type Header = generic::Header; + +/// Typical block type using `OpaqueExtrinsic`. +pub type OpaqueBlock = generic::Block; + +/// Client type used throughout the benchmarking code. +type OverheadClient = TFullClient>; + +/// Creates inherent data for a given parachain ID. +/// +/// This function constructs the inherent data required for block execution, +/// including the relay chain state and validation data. Not all of these +/// inherents are required for every chain. The runtime will pick the ones +/// it requires based on their identifier. +fn create_inherent_data + HeaderBackend, Block: BlockT>( + client: &Arc, + chain_type: &ChainType, +) -> InherentData { + let genesis = client.usage_info().chain.best_hash; + let header = client.header(genesis).unwrap().unwrap(); + + let mut inherent_data = InherentData::new(); + + // Para inherent can only makes sense when we are handling a parachain. + if let Parachain(para_id) = chain_type { + let parachain_validation_data_provider = MockValidationDataInherentDataProvider::<()> { + para_id: ParaId::from(*para_id), + current_para_block_head: Some(header.encode().into()), + relay_offset: 1, + ..Default::default() + }; + let _ = futures::executor::block_on( + parachain_validation_data_provider.provide_inherent_data(&mut inherent_data), + ); + } + + // Parachain inherent that is used on relay chains to perform parachain validation. + let para_inherent = polkadot_primitives::InherentData { + bitfields: Vec::new(), + backed_candidates: Vec::new(), + disputes: Vec::new(), + parent_header: header, + }; + + // Timestamp inherent that is very common in substrate chains. + let timestamp = sp_timestamp::InherentDataProvider::new(std::time::Duration::default().into()); + + let _ = futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data)); + let _ = + inherent_data.put_data(polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER, ¶_inherent); + + inherent_data +} + +/// Identifies what kind of chain we are dealing with. +/// +/// Chains containing the `ParachainSystem` and `ParachainInfo` pallet are considered parachains. +/// Chains containing the `ParaInherent` pallet are considered relay chains. +fn identify_chain(metadata: &Metadata, para_id: Option) -> ChainType { + let parachain_info_exists = metadata.pallet_by_name("ParachainInfo").is_some(); + let parachain_system_exists = metadata.pallet_by_name("ParachainSystem").is_some(); + let para_inherent_exists = metadata.pallet_by_name("ParaInherent").is_some(); + + log::debug!("{} ParachainSystem", if parachain_system_exists { "✅" } else { "❌" }); + log::debug!("{} ParachainInfo", if parachain_info_exists { "✅" } else { "❌" }); + log::debug!("{} ParaInherent", if para_inherent_exists { "✅" } else { "❌" }); + + let chain_type = if parachain_system_exists && parachain_info_exists { + Parachain(para_id.unwrap_or(DEFAULT_PARA_ID)) + } else if para_inherent_exists { + Relaychain + } else { + Unknown + }; + + log::info!(target: LOG_TARGET, "Identified Chain type from metadata: {}", chain_type); + + chain_type +} + +#[derive(Deserialize, Serialize, Clone, ChainSpecExtension)] +pub struct ParachainExtension { + /// The id of the Parachain. + pub para_id: Option, +} + +impl OverheadCmd { + fn state_handler_from_cli( + &self, + chain_spec_from_api: Option>, + ) -> Result<(GenesisStateHandler, Option)> { + let genesis_builder_to_source = || match self.params.genesis_builder { + Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => + SpecGenesisSource::Runtime(self.params.genesis_builder_preset.clone()), + Some(GenesisBuilderPolicy::SpecGenesis) | None => { + log::warn!(target: LOG_TARGET, "{WARN_SPEC_GENESIS_CTOR}"); + SpecGenesisSource::SpecJson + }, + }; + + // First handle chain-spec passed in via API parameter. + if let Some(chain_spec) = chain_spec_from_api { + log::debug!(target: LOG_TARGET, "Initializing state handler with chain-spec from API: {:?}", chain_spec); + + let source = genesis_builder_to_source(); + return Ok((GenesisStateHandler::ChainSpec(chain_spec, source), self.params.para_id)) + }; + + // Handle chain-spec passed in via CLI. + if let Some(chain_spec_path) = &self.shared_params.chain { + log::debug!(target: LOG_TARGET, + "Initializing state handler with chain-spec from path: {:?}", + chain_spec_path + ); + let (chain_spec, para_id_from_chain_spec) = + genesis_state::chain_spec_from_path::(chain_spec_path.to_string().into())?; + + let source = genesis_builder_to_source(); + + return Ok(( + GenesisStateHandler::ChainSpec(chain_spec, source), + self.params.para_id.or(para_id_from_chain_spec), + )) + }; + + // Check for runtimes. In general, we make sure that `--runtime` and `--chain` are + // incompatible on the CLI level. + if let Some(runtime_path) = &self.params.runtime { + log::debug!(target: LOG_TARGET, "Initializing state handler with runtime from path: {:?}", runtime_path); + + let runtime_blob = fs::read(runtime_path)?; + return Ok(( + GenesisStateHandler::Runtime( + runtime_blob, + Some(self.params.genesis_builder_preset.clone()), + ), + self.params.para_id, + )) + }; + + Err("Neither a runtime nor a chain-spec were specified".to_string().into()) + } + + fn check_args( + &self, + chain_spec: &Option>, + ) -> std::result::Result<(), (ErrorKind, String)> { + if chain_spec.is_none() && + self.params.runtime.is_none() && + self.shared_params.chain.is_none() + { + return Err(( + ErrorKind::MissingRequiredArgument, + "Provide either a runtime via `--runtime` or a chain spec via `--chain`" + .to_string(), + )) + } + + match self.params.genesis_builder { + Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::SpecRuntime) => + if chain_spec.is_none() && self.shared_params.chain.is_none() { + return Err(( + ErrorKind::MissingRequiredArgument, + "Provide a chain spec via `--chain`.".to_string(), + )) + }, + _ => {}, + }; + Ok(()) + } + + /// Run the overhead benchmark with the default extrinsic builder. + /// + /// This will use [SubstrateRemarkBuilder] to build the extrinsic. It is + /// designed to match common configurations found in substrate chains. + pub fn run_with_default_builder_and_spec( + &self, + chain_spec: Option>, + ) -> Result<()> + where + Block: BlockT, + ExtraHF: HostFunctions, + { + self.run_with_extrinsic_builder_and_spec::( + Box::new(|metadata, hash, version| { + let genesis = subxt::utils::H256::from(hash.to_fixed_bytes()); + Box::new(SubstrateRemarkBuilder::new(metadata, genesis, version)) as Box<_> + }), + chain_spec, + ) + } + + /// Run the benchmark overhead command. + /// + /// The provided [ExtrinsicBuilder] will be used to build extrinsics for + /// block-building. It is expected that the provided implementation builds + /// a `System::remark` extrinsic. + pub fn run_with_extrinsic_builder_and_spec( + &self, + ext_builder_provider: Box< + dyn FnOnce(Metadata, Block::Hash, RuntimeVersion) -> Box, + >, + chain_spec: Option>, + ) -> Result<()> + where + Block: BlockT, + ExtraHF: HostFunctions, + { + if let Err((error_kind, msg)) = self.check_args(&chain_spec) { + let mut cmd = OverheadCmd::command(); + cmd.error(error_kind, msg).exit(); + }; + + let (state_handler, para_id) = + self.state_handler_from_cli::<(ParachainHostFunctions, ExtraHF)>(chain_spec)?; + + let executor = WasmExecutor::<(ParachainHostFunctions, ExtraHF)>::builder() + .with_allow_missing_host_functions(true) + .build(); + + let metadata = + fetch_latest_metadata_from_code_blob(&executor, state_handler.get_code_bytes()?)?; + + // At this point we know what kind of chain we are dealing with. + let chain_type = identify_chain(&metadata, para_id); + + // If we are dealing with a parachain, make sure that the para id in genesis will + // match what we expect. + let genesis_patcher = match chain_type { + Parachain(para_id) => + Some(Box::new(move |value| patch_genesis(value, Some(para_id))) as Box<_>), + _ => None, + }; + + let client = self.build_client_components::( + state_handler.build_storage::<(ParachainHostFunctions, ExtraHF)>(genesis_patcher)?, + executor, + &chain_type, + )?; + + let inherent_data = create_inherent_data(&client, &chain_type); + + let (ext_builder, runtime_name) = { + let genesis = client.usage_info().chain.best_hash; + let version = client.runtime_api().version(genesis).unwrap(); + let runtime_name = version.spec_name; + let runtime_version = RuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }; + + (ext_builder_provider(metadata, genesis, runtime_version), runtime_name) + }; + + self.run( + runtime_name.to_string(), + client, + inherent_data, + Default::default(), + &*ext_builder, + chain_type.requires_proof_recording(), + ) + } + + /// Run the benchmark overhead command. + pub fn run_with_extrinsic_builder( + &self, + ext_builder_provider: Box< + dyn FnOnce(Metadata, Block::Hash, RuntimeVersion) -> Box, + >, + ) -> Result<()> + where + Block: BlockT, + ExtraHF: HostFunctions, + { + self.run_with_extrinsic_builder_and_spec::(ext_builder_provider, None) + } + + fn build_client_components( + &self, + genesis_storage: Storage, + executor: WasmExecutor, + chain_type: &ChainType, + ) -> Result>> + where + Block: BlockT, + HF: HostFunctions, + { + let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone())); + + let base_path = match &self.shared_params.base_path { + None => BasePath::new_temp_dir()?, + Some(path) => BasePath::from(path.clone()), + }; + + let database_source = self.database_config( + &base_path.path().to_path_buf(), + self.database_cache_size()?.unwrap_or(1024), + self.database()?.unwrap_or(Database::RocksDb), + )?; + + let backend = new_db_backend(DatabaseSettings { + trie_cache_maximum_size: self.trie_cache_maximum_size()?, + state_pruning: None, + blocks_pruning: BlocksPruning::KeepAll, + source: database_source, + })?; + + let genesis_block_builder = GenesisBlockBuilder::new_with_storage( + genesis_storage, + true, + backend.clone(), + executor.clone(), + )?; + + let tokio_runtime = sc_cli::build_runtime()?; + let task_manager = TaskManager::new(tokio_runtime.handle().clone(), None) + .map_err(|_| "Unable to build task manager")?; + + let client: Arc> = Arc::new(new_client( + backend.clone(), + executor, + genesis_block_builder, + Default::default(), + Default::default(), + extensions, + Box::new(task_manager.spawn_handle()), + None, + None, + ClientConfig { + offchain_worker_enabled: false, + offchain_indexing_api: false, + wasm_runtime_overrides: None, + no_genesis: false, + wasm_runtime_substitutes: Default::default(), + enable_import_proof_recording: chain_type.requires_proof_recording(), + }, + )?); + + Ok(client) + } + + /// Measure the per-block and per-extrinsic execution overhead. + /// + /// Writes the results to console and into two instances of the + /// `weights.hbs` template, one for each benchmark. + pub fn run( + &self, + chain_name: String, + client: Arc, + inherent_data: sp_inherents::InherentData, + digest_items: Vec, + ext_builder: &dyn ExtrinsicBuilder, + should_record_proof: bool, + ) -> Result<()> + where + Block: BlockT, + C: ProvideRuntimeApi + + CallApiAt + + UsageProvider + + sp_blockchain::HeaderBackend, + C::Api: ApiExt + BlockBuilderApi, + { + if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { + return Err(format!("The extrinsic builder is required to build `System::Remark` extrinsics but builds `{}` extrinsics instead", ext_builder.name()).into()); + } + + let bench = Benchmark::new( + client, + self.params.bench.clone(), + inherent_data, + digest_items, + should_record_proof, + ); + + // per-block execution overhead + { + let (stats, proof_size) = bench.bench_block()?; + info!(target: LOG_TARGET, "Per-block execution overhead [ns]:\n{:?}", stats); + let template = TemplateData::new( + BenchmarkType::Block, + &chain_name, + &self.params, + &stats, + proof_size, + )?; + template.write(&self.params.weight.weight_path)?; + } + // per-extrinsic execution overhead + { + let (stats, proof_size) = bench.bench_extrinsic(ext_builder)?; + info!(target: LOG_TARGET, "Per-extrinsic execution overhead [ns]:\n{:?}", stats); + let template = TemplateData::new( + BenchmarkType::Extrinsic, + &chain_name, + &self.params, + &stats, + proof_size, + )?; + template.write(&self.params.weight.weight_path)?; + } + + Ok(()) + } +} + +impl BenchmarkType { + /// Short name of the benchmark type. + pub(crate) fn short_name(&self) -> &'static str { + match self { + Self::Extrinsic => "extrinsic", + Self::Block => "block", + } + } + + /// Long name of the benchmark type. + pub(crate) fn long_name(&self) -> &'static str { + match self { + Self::Extrinsic => "ExtrinsicBase", + Self::Block => "BlockExecution", + } + } +} + +#[derive(Clone, PartialEq, Debug)] +enum ChainType { + Parachain(u32), + Relaychain, + Unknown, +} + +impl Display for ChainType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + ChainType::Parachain(id) => write!(f, "Parachain(paraid = {})", id), + ChainType::Relaychain => write!(f, "Relaychain"), + ChainType::Unknown => write!(f, "Unknown"), + } + } +} + +impl ChainType { + fn requires_proof_recording(&self) -> bool { + match self { + Parachain(_) => true, + Relaychain => false, + Unknown => false, + } + } +} + +/// Patch the parachain id into the genesis config. This is necessary since the inherents +/// also contain a parachain id and they need to match. +fn patch_genesis(mut input_value: Value, para_id: Option) -> Value { + // If we identified a parachain we should patch a parachain id into the genesis config. + // This ensures compatibility with the inherents that we provide to successfully build a + // block. + if let Some(para_id) = para_id { + sc_chain_spec::json_patch::merge( + &mut input_value, + json!({ + "parachainInfo": { + "parachainId": para_id, + } + }), + ); + log::debug!(target: LOG_TARGET, "Genesis Config Json"); + log::debug!(target: LOG_TARGET, "{}", input_value); + } + input_value +} + +// Boilerplate +impl CliConfiguration for OverheadCmd { + fn shared_params(&self) -> &SharedParams { + &self.shared_params + } + + fn import_params(&self) -> Option<&ImportParams> { + Some(&self.import_params) + } + + fn base_path(&self) -> Result> { + Ok(Some(BasePath::new_temp_dir()?)) + } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.params.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + overhead::command::{identify_chain, ChainType, ParachainHostFunctions, DEFAULT_PARA_ID}, + OverheadCmd, + }; + use clap::Parser; + use sc_executor::WasmExecutor; + + #[test] + fn test_chain_type_relaychain() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + let code_bytes = westend_runtime::WASM_BINARY + .expect("To run this test, build the wasm binary of westend-runtime") + .to_vec(); + let metadata = + super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let chain_type = identify_chain(&metadata, None); + assert_eq!(chain_type, ChainType::Relaychain); + assert_eq!(chain_type.requires_proof_recording(), false); + } + + #[test] + fn test_chain_type_parachain() { + 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 chain_type = identify_chain(&metadata, Some(100)); + assert_eq!(chain_type, ChainType::Parachain(100)); + assert!(chain_type.requires_proof_recording()); + assert_eq!(identify_chain(&metadata, None), ChainType::Parachain(DEFAULT_PARA_ID)); + } + + #[test] + fn test_chain_type_custom() { + let executor: WasmExecutor = WasmExecutor::builder().build(); + 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 = + super::fetch_latest_metadata_from_code_blob(&executor, code_bytes.into()).unwrap(); + let chain_type = identify_chain(&metadata, None); + assert_eq!(chain_type, ChainType::Unknown); + assert_eq!(chain_type.requires_proof_recording(), false); + } + + fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { + let cmd = OverheadCmd::try_parse_from(args)?; + assert!(cmd.check_args(&None).is_ok()); + Ok(()) + } + + fn cli_fail(args: &[&str]) { + let cmd = OverheadCmd::try_parse_from(args); + if let Ok(cmd) = cmd { + assert!(cmd.check_args(&None).is_err()); + } + } + + #[test] + fn test_cli_conflicts() -> Result<(), clap::Error> { + // Runtime tests + cli_succeed(&["test", "--runtime", "path/to/runtime", "--genesis-builder", "runtime"])?; + cli_succeed(&["test", "--runtime", "path/to/runtime"])?; + cli_succeed(&[ + "test", + "--runtime", + "path/to/runtime", + "--genesis-builder-preset", + "preset", + ])?; + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec"]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-genesis"]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-runtime"]); + + // Spec tests + cli_succeed(&["test", "--chain", "path/to/spec"])?; + cli_succeed(&["test", "--chain", "path/to/spec", "--genesis-builder", "spec"])?; + cli_succeed(&["test", "--chain", "path/to/spec", "--genesis-builder", "spec-genesis"])?; + cli_succeed(&["test", "--chain", "path/to/spec", "--genesis-builder", "spec-runtime"])?; + cli_fail(&["test", "--chain", "path/to/spec", "--genesis-builder", "none"]); + cli_fail(&["test", "--chain", "path/to/spec", "--genesis-builder", "runtime"]); + cli_fail(&[ + "test", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + "--genesis-builder-preset", + "preset", + ]); + Ok(()) + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs new file mode 100644 index 000000000000..653908a5a205 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/fake_runtime_api.rs @@ -0,0 +1,109 @@ +// 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. + +//! A fake runtime struct that allows us to instantiate a client. +//! Has all the required runtime APIs implemented to satisfy trait bounds, +//! but the methods are never called since we use WASM exclusively. + +use sp_core::OpaqueMetadata; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, Block as BlockT}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, OpaqueExtrinsic, +}; + +/// Block number +type BlockNumber = u32; +/// Opaque block header type. +type Header = generic::Header; +/// Opaque block type. +type Block = generic::Block; + +#[allow(unused)] +pub struct Runtime; + +sp_api::impl_runtime_apis! { + 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!() + } + } + + impl sp_api::Metadata for Runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + + fn metadata_at_version(_: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> Vec { + unimplemented!() + } + } + impl sp_block_builder::BlockBuilder for Runtime { + fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { + unimplemented!() + } + + fn finalize_block() -> ::Header { + unimplemented!() + } + + fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { + unimplemented!() + } + + fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { + unimplemented!() + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { + fn validate_transaction( + _: TransactionSource, + _: ::Extrinsic, + _: ::Hash, + ) -> TransactionValidity { + unimplemented!() + } + } + + impl sp_genesis_builder::GenesisBuilder for Runtime { + fn build_state(_: Vec) -> sp_genesis_builder::Result { + unimplemented!() + } + + fn get_preset(_id: &Option) -> Option> { + unimplemented!() + } + + fn preset_names() -> Vec { + unimplemented!() + } + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs index 00cde66fd722..89c23d1fb6c1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/mod.rs @@ -15,7 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod cmd; +pub mod command; pub mod template; -pub use cmd::OverheadCmd; +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 new file mode 100644 index 000000000000..a1d5f282d9f8 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/remark_builder.rs @@ -0,0 +1,122 @@ +// 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 crate::extrinsic::ExtrinsicBuilder; +use codec::Decode; +use sc_client_api::UsageProvider; +use sp_api::{ApiExt, Core, Metadata, ProvideRuntimeApi}; +use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; +use std::sync::Arc; +use subxt::{ + client::RuntimeVersion as SubxtRuntimeVersion, + config::substrate::SubstrateExtrinsicParamsBuilder, Config, OfflineClient, SubstrateConfig, +}; + +pub type SubstrateRemarkBuilder = DynamicRemarkBuilder; + +/// Remark builder that can be used to build simple extrinsics for +/// FRAME-based runtimes. +pub struct DynamicRemarkBuilder { + offline_client: OfflineClient, +} + +impl> DynamicRemarkBuilder { + /// Initializes a new remark builder from a client. + /// + /// This will first fetch metadata and runtime version from the runtime and then + /// construct an offline client that provides the extrinsics. + pub fn new_from_client(client: Arc) -> sc_cli::Result + where + Block: BlockT, + Client: UsageProvider + ProvideRuntimeApi, + Client::Api: Metadata + Core, + { + let genesis = client.usage_info().chain.best_hash; + let api = client.runtime_api(); + + let Ok(Some(metadata_api_version)) = api.api_version::>(genesis) else { + return Err("Unable to fetch metadata runtime API version.".to_string().into()); + }; + + 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 { + return Err("Unable to fetch metadata versions".to_string().into()); + }; + + let latest = supported_metadata_versions + .pop() + .ok_or("No metadata version supported".to_string())?; + + api.metadata_at_version(genesis, latest) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + .ok_or("Unable to decode metadata".to_string())? + } else { + // Fall back to using the non-versioned metadata API. + api.metadata(genesis) + .map_err(|e| format!("Unable to fetch metadata: {:?}", e))? + }; + + let version = api.version(genesis).unwrap(); + let runtime_version = SubxtRuntimeVersion { + spec_version: version.spec_version, + transaction_version: version.transaction_version, + }; + let metadata = subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?; + let genesis = subxt::utils::H256::from(genesis.to_fixed_bytes()); + + Ok(Self { offline_client: OfflineClient::new(genesis, runtime_version, metadata) }) + } +} + +impl DynamicRemarkBuilder { + /// Constructs a new remark builder. + pub fn new( + metadata: subxt::Metadata, + genesis_hash: C::Hash, + runtime_version: SubxtRuntimeVersion, + ) -> Self { + Self { offline_client: OfflineClient::new(genesis_hash, runtime_version, metadata) } + } +} + +impl ExtrinsicBuilder for DynamicRemarkBuilder { + fn pallet(&self) -> &str { + "system" + } + + fn extrinsic(&self) -> &str { + "remark" + } + + fn build(&self, nonce: u32) -> std::result::Result { + let signer = subxt_signer::sr25519::dev::alice(); + let dynamic_tx = subxt::dynamic::tx("System", "remark", vec![Vec::::new()]); + + let params = SubstrateExtrinsicParamsBuilder::new().nonce(nonce.into()).build(); + + // Default transaction parameters assume a nonce of 0. + let transaction = self + .offline_client + .tx() + .create_signed_offline(&dynamic_tx, &signer, params) + .unwrap(); + let mut encoded = transaction.into_encoded(); + + OpaqueExtrinsic::from_bytes(&mut encoded).map_err(|_| "Unable to construct OpaqueExtrinsic") + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs new file mode 100644 index 000000000000..c498da38afb0 --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/runtime_utilities.rs @@ -0,0 +1,141 @@ +// 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 codec::{Decode, Encode}; +use sc_executor::WasmExecutor; +use sp_core::{ + traits::{CallContext, CodeExecutor, FetchRuntimeCode, RuntimeCode}, + OpaqueMetadata, +}; +use sp_state_machine::BasicExternalities; +use sp_wasm_interface::HostFunctions; +use std::borrow::Cow; + +/// 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 { + let runtime_caller = RuntimeCaller::new(executor, code_bytes); + let version_result = runtime_caller.call("Metadata_metadata_versions", ()); + + let opaque_metadata: OpaqueMetadata = 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())?; + Option::::decode(&mut encoded.as_slice())? + .ok_or_else(|| "Metadata not found".to_string())? + }, + Err(_) => { + let encoded = runtime_caller + .call("Metadata_metadata", ()) + .map_err(|_| "Unable to fetch metadata from blob".to_string())?; + Decode::decode(&mut encoded.as_slice())? + }, + }; + + Ok(subxt::Metadata::decode(&mut (*opaque_metadata).as_slice())?) +} + +struct BasicCodeFetcher<'a> { + code: Cow<'a, [u8]>, + hash: Vec, +} + +impl<'a> FetchRuntimeCode for BasicCodeFetcher<'a> { + fn fetch_runtime_code(&self) -> Option> { + Some(self.code.as_ref().into()) + } +} + +impl<'a> BasicCodeFetcher<'a> { + pub 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> { + RuntimeCode { + code_fetcher: self as &'a dyn FetchRuntimeCode, + heap_pages: None, + hash: self.hash.clone(), + } + } +} + +/// Simple utility that is used to call into the runtime. +struct RuntimeCaller<'a, 'b, HF: HostFunctions> { + executor: &'b WasmExecutor, + code_fetcher: BasicCodeFetcher<'a>, +} + +impl<'a, 'b, HF: HostFunctions> RuntimeCaller<'a, 'b, HF> { + 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> { + let mut ext = BasicExternalities::default(); + self.executor + .call( + &mut ext, + &self.code_fetcher.runtime_code(), + method, + &data.encode(), + CallContext::Offchain, + ) + .0 + } +} + +#[cfg(test)] +mod tests { + use crate::overhead::command::ParachainHostFunctions; + use codec::Decode; + use sc_executor::WasmExecutor; + use sp_version::RuntimeVersion; + + #[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(); + assert!(metadata.pallet_by_name("ParachainInfo").is_some()); + } + + #[test] + fn test_runtime_caller_can_call_into_runtime() { + 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 runtime_caller = super::RuntimeCaller::new(&executor, code_bytes.into()); + let runtime_version = runtime_caller + .call("Core_version", ()) + .expect("Should be able to call runtime_version"); + let _runtime_version: RuntimeVersion = Decode::decode(&mut runtime_version.as_slice()) + .expect("Should be able to decode runtime version"); + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs b/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs index 7c8c92b07d74..08227607951b 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -19,7 +19,6 @@ //! it into the `weights.hbs` template. use sc_cli::Result; -use sc_service::Configuration; use handlebars::Handlebars; use log::info; @@ -27,7 +26,7 @@ use serde::Serialize; use std::{env, fs, path::PathBuf}; use crate::{ - overhead::cmd::{BenchmarkType, OverheadParams}, + overhead::command::{BenchmarkType, OverheadParams}, shared::{Stats, UnderscoreHelper}, }; @@ -59,19 +58,22 @@ pub(crate) struct TemplateData { params: OverheadParams, /// Stats about the benchmark result. stats: Stats, - /// The resulting weight in ns. - weight: u64, + /// The resulting ref time weight. + ref_time: u64, + /// The size of the proof weight. + proof_size: u64, } impl TemplateData { /// Returns a new [`Self`] from the given params. pub(crate) fn new( t: BenchmarkType, - cfg: &Configuration, + chain_name: &String, params: &OverheadParams, stats: &Stats, + proof_size: u64, ) -> Result { - let weight = params.weight.calc_weight(stats)?; + let ref_time = params.weight.calc_weight(stats)?; let header = params .header .as_ref() @@ -82,7 +84,7 @@ impl TemplateData { Ok(TemplateData { short_name: t.short_name().into(), long_name: t.long_name().into(), - runtime_name: cfg.chain_spec.name().into(), + runtime_name: chain_name.to_owned(), version: VERSION.into(), date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), hostname: params.hostinfo.hostname(), @@ -91,7 +93,8 @@ impl TemplateData { args: env::args().collect::>(), params: params.clone(), stats: stats.clone(), - weight, + ref_time, + proof_size, }) } diff --git a/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs index 6e364facc12f..1596bb57a41a 100644 --- a/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/substrate/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -18,9 +18,9 @@ use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; parameter_types! { {{#if (eq short_name "block")}} - /// Time to execute an empty block. + /// Weight of executing an empty block. {{else}} - /// Time to execute a NO-OP extrinsic, for example `System::remark`. + /// Weight of executing a NO-OP extrinsic, for example `System::remark`. {{/if}} /// Calculated by multiplying the *{{params.weight.weight_metric}}* with `{{params.weight.weight_mul}}` and adding `{{params.weight.weight_add}}`. /// @@ -35,7 +35,7 @@ parameter_types! { /// 95th: {{underscore stats.p95}} /// 75th: {{underscore stats.p75}} pub const {{long_name}}Weight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore weight}}), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul({{underscore ref_time}}), {{underscore proof_size}}); } #[cfg(test)] diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index f1499f41c2ea..0c068fc585ba 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -19,7 +19,14 @@ use super::{ types::{ComponentRange, ComponentRangeMap}, writer, ListOutput, PalletCmd, }; -use crate::pallet::{types::FetchedCode, GenesisBuilderPolicy}; +use crate::{ + pallet::{types::FetchedCode, GenesisBuilderPolicy}, + shared::{ + genesis_state, + genesis_state::{GenesisStateHandler, SpecGenesisSource, WARN_SPEC_GENESIS_CTOR}, + }, +}; +use clap::{error::ErrorKind, CommandFactory}; use codec::{Decode, Encode}; use frame_benchmarking::{ Analysis, BenchmarkBatch, BenchmarkBatchSplitResults, BenchmarkList, BenchmarkParameter, @@ -27,7 +34,6 @@ use frame_benchmarking::{ }; use frame_support::traits::StorageInfo; use linked_hash_map::LinkedHashMap; -use sc_chain_spec::GenesisConfigBuilderRuntimeCaller; use sc_cli::{execution_method_from_cli, ChainSpec, CliConfiguration, Result, SharedParams}; use sc_client_db::BenchmarkingState; use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; @@ -36,17 +42,17 @@ use sp_core::{ testing::{TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, - traits::{CallContext, CodeExecutor, ReadRuntimeVersionExt}, + traits::{CallContext, CodeExecutor, ReadRuntimeVersionExt, WrappedRuntimeCode}, Hasher, }; use sp_externalities::Extensions; use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; use sp_runtime::traits::Hash; use sp_state_machine::StateMachine; -use sp_storage::{well_known_keys::CODE, Storage}; use sp_trie::{proof_size_extension::ProofSizeExt, recorder::Recorder}; use sp_wasm_interface::HostFunctions; use std::{ + borrow::Cow, collections::{BTreeMap, BTreeSet, HashMap}, fmt::Debug, fs, @@ -57,6 +63,8 @@ use std::{ /// Logging target const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; +type SubstrateAndExtraHF = + (sp_io::SubstrateHostFunctions, frame_benchmarking::benchmarking::HostFunctions, T); /// How the PoV size of a storage item should be estimated. #[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy)] pub enum PovEstimationMode { @@ -88,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)>, @@ -144,23 +153,11 @@ 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"; -/// When the runtime could not build the genesis storage. -const ERROR_CANNOT_BUILD_GENESIS: &str = "The runtime returned \ -an error when trying to build the genesis storage. Please ensure that all pallets \ -define a genesis config that can be built. This can be tested with: \ -https://github.com/paritytech/polkadot-sdk/pull/3412"; - -/// Warn when using the chain spec to generate the genesis state. -const WARN_SPEC_GENESIS_CTOR: &'static str = "Using the chain spec instead of the runtime to \ -generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`--local` argument, \ -point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ -become a hard error any time after December 2024."; - impl PalletCmd { /// Runs the command and benchmarks a pallet. #[deprecated( @@ -176,6 +173,61 @@ impl PalletCmd { self.run_with_spec::(Some(config.chain_spec)) } + fn state_handler_from_cli( + &self, + chain_spec_from_api: Option>, + ) -> Result { + let genesis_builder_to_source = || match self.genesis_builder { + Some(GenesisBuilderPolicy::Runtime) | Some(GenesisBuilderPolicy::SpecRuntime) => + SpecGenesisSource::Runtime(self.genesis_builder_preset.clone()), + Some(GenesisBuilderPolicy::SpecGenesis) | None => { + log::warn!(target: LOG_TARGET, "{WARN_SPEC_GENESIS_CTOR}"); + SpecGenesisSource::SpecJson + }, + Some(GenesisBuilderPolicy::None) => SpecGenesisSource::None, + }; + + // First handle chain-spec passed in via API parameter. + if let Some(chain_spec) = chain_spec_from_api { + log::debug!("Initializing state handler with chain-spec from API: {:?}", chain_spec); + + let source = genesis_builder_to_source(); + return Ok(GenesisStateHandler::ChainSpec(chain_spec, source)) + }; + + // Handle chain-spec passed in via CLI. + if let Some(chain_spec_path) = &self.shared_params.chain { + log::debug!( + "Initializing state handler with chain-spec from path: {:?}", + chain_spec_path + ); + let (chain_spec, _) = + genesis_state::chain_spec_from_path::(chain_spec_path.to_string().into())?; + + let source = genesis_builder_to_source(); + + return Ok(GenesisStateHandler::ChainSpec(chain_spec, source)) + }; + + // Check for runtimes. In general, we make sure that `--runtime` and `--chain` are + // incompatible on the CLI level. + if let Some(runtime_path) = &self.runtime { + log::debug!("Initializing state handler with runtime from path: {:?}", runtime_path); + + let runtime_blob = fs::read(runtime_path)?; + return if let Some(GenesisBuilderPolicy::None) = self.genesis_builder { + Ok(GenesisStateHandler::Runtime(runtime_blob, None)) + } else { + Ok(GenesisStateHandler::Runtime( + runtime_blob, + Some(self.genesis_builder_preset.clone()), + )) + } + }; + + Err("Neither a runtime nor a chain-spec were specified".to_string().into()) + } + /// Runs the pallet benchmarking command. pub fn run_with_spec( &self, @@ -185,7 +237,11 @@ impl PalletCmd { Hasher: Hash, ExtraHostFunctions: HostFunctions, { - self.check_args()?; + if let Err((error_kind, msg)) = self.check_args(&chain_spec) { + let mut cmd = PalletCmd::command(); + cmd.error(error_kind, msg).exit(); + }; + let _d = self.execution.as_ref().map(|exec| { // We print the error at the end, since there is often A LOT of output. sp_core::defer::DeferGuard::new(move || { @@ -210,7 +266,10 @@ impl PalletCmd { return self.output_from_results(&batches) } - let genesis_storage = self.genesis_storage::(&chain_spec)?; + let state_handler = + self.state_handler_from_cli::>(chain_spec)?; + let genesis_storage = + state_handler.build_storage::>(None)?; let cache_size = Some(self.database_cache_size as usize); let state_with_tracking = BenchmarkingState::::new( @@ -239,18 +298,41 @@ impl PalletCmd { let runtime_code = runtime.code()?; let alloc_strategy = self.alloc_strategy(runtime_code.heap_pages); - let executor = WasmExecutor::<( - sp_io::SubstrateHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, - ExtraHostFunctions, - )>::builder() - .with_execution_method(method) - .with_allow_missing_host_functions(self.allow_missing_host_functions) - .with_onchain_heap_alloc_strategy(alloc_strategy) - .with_offchain_heap_alloc_strategy(alloc_strategy) - .with_max_runtime_instances(2) - .with_runtime_cache_size(2) - .build(); + let executor = WasmExecutor::>::builder() + .with_execution_method(method) + .with_allow_missing_host_functions(self.allow_missing_host_functions) + .with_onchain_heap_alloc_strategy(alloc_strategy) + .with_offchain_heap_alloc_strategy(alloc_strategy) + .with_max_runtime_instances(2) + .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( @@ -264,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. @@ -284,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!( @@ -338,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; @@ -353,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, @@ -368,12 +467,12 @@ impl PalletCmd { "dispatch a benchmark", ) { Err(e) => { - log::error!("Error executing and verifying runtime benchmark: {}", e); + log::error!(target: LOG_TARGET, "Error executing and verifying runtime benchmark: {}", e); failed.push((pallet.clone(), extrinsic.clone())); continue 'outer }, Ok(Err(e)) => { - log::error!("Error executing and verifying runtime benchmark: {}", e); + log::error!(target: LOG_TARGET, "Error executing and verifying runtime benchmark: {}", e); failed.push((pallet.clone(), extrinsic.clone())); continue 'outer }, @@ -393,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, @@ -408,12 +500,12 @@ impl PalletCmd { "dispatch a benchmark", ) { Err(e) => { - log::error!("Error executing runtime benchmark: {}", e); + log::error!(target: LOG_TARGET, "Error executing runtime benchmark: {}", e); failed.push((pallet.clone(), extrinsic.clone())); continue 'outer }, Ok(Err(e)) => { - log::error!("Benchmark {pallet}::{extrinsic} failed: {e}",); + log::error!(target: LOG_TARGET, "Benchmark {pallet}::{extrinsic} failed: {e}",); failed.push((pallet.clone(), extrinsic.clone())); continue 'outer }, @@ -435,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, @@ -502,43 +587,41 @@ impl PalletCmd { } fn select_benchmarks_to_run(&self, list: Vec) -> Result> { - let pallet = self.pallet.clone().unwrap_or_default(); - let pallet = pallet.as_bytes(); - let extrinsic = self.extrinsic.clone().unwrap_or_default(); let extrinsic_split: Vec<&str> = extrinsic.split(',').collect(); let extrinsics: Vec<_> = extrinsic_split.iter().map(|x| x.trim().as_bytes()).collect(); // Use the benchmark list and the user input to determine the set of benchmarks to run. let mut benchmarks_to_run = Vec::new(); - list.iter() - .filter(|item| pallet.is_empty() || pallet == &b"*"[..] || pallet == &item.pallet[..]) - .for_each(|item| { - for benchmark in &item.benchmarks { - let benchmark_name = &benchmark.name; - if extrinsic.is_empty() || - extrinsic.as_bytes() == &b"*"[..] || - extrinsics.contains(&&benchmark_name[..]) - { - benchmarks_to_run.push(( - item.pallet.clone(), - benchmark.name.clone(), - benchmark.components.clone(), - benchmark.pov_modes.clone(), - )) - } + list.iter().filter(|item| self.pallet_selected(&item.pallet)).for_each(|item| { + for benchmark in &item.benchmarks { + let benchmark_name = &benchmark.name; + if extrinsic.is_empty() || + extrinsic.as_bytes() == &b"*"[..] || + extrinsics.contains(&&benchmark_name[..]) + { + benchmarks_to_run.push(( + item.pallet.clone(), + item.instance.clone(), + benchmark.name.clone(), + benchmark.components.clone(), + benchmark.pov_modes.clone(), + )) } - }); + } + }); // 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 @@ -558,95 +641,14 @@ impl PalletCmd { Ok(benchmarks_to_run) } - /// Build the genesis storage by either the Genesis Builder API, chain spec or nothing. - /// - /// Behaviour can be controlled by the `--genesis-builder` flag. - fn genesis_storage( - &self, - chain_spec: &Option>, - ) -> Result { - Ok(match (self.genesis_builder, self.runtime.as_ref()) { - (Some(GenesisBuilderPolicy::None), Some(_)) => return Err("Cannot use `--genesis-builder=none` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::None), None) => Storage::default(), - (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), Some(_)) => - return Err("Cannot use `--genesis-builder=spec-genesis` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::Spec), None) | (None, None) => { - log::warn!("{WARN_SPEC_GENESIS_CTOR}"); - let Some(chain_spec) = chain_spec else { - return Err("No chain spec specified to generate the genesis state".into()); - }; - - let storage = chain_spec - .build_storage() - .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}"))?; - - storage - }, - (Some(GenesisBuilderPolicy::SpecRuntime), Some(_)) => - return Err("Cannot use `--genesis-builder=spec` with `--runtime` since the runtime would be ignored.".into()), - (Some(GenesisBuilderPolicy::SpecRuntime), None) => { - let Some(chain_spec) = chain_spec else { - return Err("No chain spec specified to generate the genesis state".into()); - }; + /// Whether this pallet should be run. + fn pallet_selected(&self, pallet: &Vec) -> bool { + let include = self.pallet.clone().unwrap_or_default(); - self.genesis_from_spec_runtime::(chain_spec.as_ref())? - }, - (Some(GenesisBuilderPolicy::Runtime), None) => return Err("Cannot use `--genesis-builder=runtime` without `--runtime`".into()), - (Some(GenesisBuilderPolicy::Runtime), Some(runtime)) | (None, Some(runtime)) => { - log::info!("Loading WASM from {}", runtime.display()); + let included = include.is_empty() || include == "*" || include.as_bytes() == pallet; + let excluded = self.exclude_pallets.iter().any(|p| p.as_bytes() == pallet); - let code = fs::read(&runtime).map_err(|e| { - format!( - "Could not load runtime file from path: {}, error: {}", - runtime.display(), - e - ) - })?; - - self.genesis_from_code::(&code)? - } - }) - } - - /// Setup the genesis state by calling the runtime APIs of the chain-specs genesis runtime. - fn genesis_from_spec_runtime( - &self, - chain_spec: &dyn ChainSpec, - ) -> Result { - log::info!("Building genesis state from chain spec runtime"); - let storage = chain_spec - .build_storage() - .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}"))?; - - let code: &Vec = - storage.top.get(CODE).ok_or("No runtime code in the genesis storage")?; - - self.genesis_from_code::(code) - } - - fn genesis_from_code(&self, code: &[u8]) -> Result { - let genesis_config_caller = GenesisConfigBuilderRuntimeCaller::<( - sp_io::SubstrateHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, - EHF, - )>::new(code); - let preset = Some(&self.genesis_builder_preset); - - let mut storage = - genesis_config_caller.get_storage_for_named_preset(preset).inspect_err(|e| { - let presets = genesis_config_caller.preset_names().unwrap_or_default(); - log::error!( - "Please pick one of the available presets with \ - `--genesis-builder-preset=`. Available presets ({}): {:?}. Error: {:?}", - presets.len(), - presets, - e - ); - })?; - - storage.top.insert(CODE.into(), code.into()); - - Ok(storage) + included && !excluded } /// Execute a state machine and decode its return value as `R`. @@ -690,10 +692,25 @@ impl PalletCmd { &self, state: &'a BenchmarkingState, ) -> Result, H>> { - log::info!("Loading WASM from state"); - let state = sp_state_machine::backend::BackendRuntimeCode::new(state); + if let Some(runtime) = self.runtime.as_ref() { + log::info!(target: LOG_TARGET, "Loading WASM from file"); + let code = fs::read(runtime).map_err(|e| { + format!( + "Could not load runtime file from path: {}, error: {}", + runtime.display(), + e + ) + })?; + let hash = sp_core::blake2_256(&code).to_vec(); + let wrapped_code = WrappedRuntimeCode(Cow::Owned(code)); - Ok(FetchedCode { state }) + Ok(FetchedCode::FromFile { wrapped_code, heap_pages: self.heap_pages, hash }) + } else { + log::info!(target: LOG_TARGET, "Loading WASM from state"); + let state = sp_state_machine::backend::BackendRuntimeCode::new(state); + + Ok(FetchedCode::FromGenesis { state }) + } } /// Allocation strategy for pallet benchmarking. @@ -927,35 +944,61 @@ impl PalletCmd { } /// Sanity check the CLI arguments. - fn check_args(&self) -> Result<()> { + fn check_args( + &self, + chain_spec: &Option>, + ) -> std::result::Result<(), (ErrorKind, String)> { if self.runtime.is_some() && self.shared_params.chain.is_some() { unreachable!("Clap should not allow both `--runtime` and `--chain` to be provided.") } + if chain_spec.is_none() && self.runtime.is_none() && self.shared_params.chain.is_none() { + return Err(( + ErrorKind::MissingRequiredArgument, + "Provide either a runtime via `--runtime` or a chain spec via `--chain`" + .to_string(), + )) + } + + match self.genesis_builder { + Some(GenesisBuilderPolicy::SpecGenesis | GenesisBuilderPolicy::SpecRuntime) => + if chain_spec.is_none() && self.shared_params.chain.is_none() { + return Err(( + ErrorKind::MissingRequiredArgument, + "Provide a chain spec via `--chain`.".to_string(), + )) + }, + _ => {}, + } + if let Some(output_path) = &self.output { if !output_path.is_dir() && output_path.file_name().is_none() { - return Err(format!( - "Output path is neither a directory nor a file: {output_path:?}" - ) - .into()) + return Err(( + ErrorKind::InvalidValue, + format!("Output path is neither a directory nor a file: {output_path:?}"), + )); } } if let Some(header_file) = &self.header { if !header_file.is_file() { - return Err(format!("Header file could not be found: {header_file:?}").into()) + return Err(( + ErrorKind::InvalidValue, + format!("Header file could not be found: {header_file:?}"), + )); }; } if let Some(handlebars_template_file) = &self.template { if !handlebars_template_file.is_file() { - return Err(format!( - "Handlebars template file could not be found: {handlebars_template_file:?}" - ) - .into()) + return Err(( + ErrorKind::InvalidValue, + format!( + "Handlebars template file could not be found: {handlebars_template_file:?}" + ), + )); }; } - Ok(()) } } @@ -1010,3 +1053,166 @@ fn list_benchmark( }, } } +#[cfg(test)] +mod tests { + use crate::pallet::PalletCmd; + use clap::Parser; + + fn cli_succeed(args: &[&str]) -> Result<(), clap::Error> { + let cmd = PalletCmd::try_parse_from(args)?; + assert!(cmd.check_args(&None).is_ok()); + Ok(()) + } + + fn cli_fail(args: &[&str]) { + let cmd = PalletCmd::try_parse_from(args); + if let Ok(cmd) = cmd { + assert!(cmd.check_args(&None).is_err()); + } + } + + #[test] + fn test_cli_conflicts() -> Result<(), clap::Error> { + // Runtime tests + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "runtime", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "none", + ])?; + cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--runtime", "path/to/runtime"])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder-preset", + "preset", + ])?; + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/runtime", + "--genesis-builder", + "spec", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec-genesis", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--runtime", + "path/to/spec", + "--genesis-builder", + "spec-runtime", + ]); + cli_fail(&["test", "--runtime", "path/to/spec", "--genesis-builder", "spec-genesis"]); + + // Spec tests + cli_succeed(&["test", "--extrinsic", "", "--pallet", "", "--chain", "path/to/spec"])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec-genesis", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "spec-runtime", + ])?; + cli_succeed(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "none", + ])?; + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + ]); + cli_fail(&[ + "test", + "--extrinsic", + "", + "--pallet", + "", + "--chain", + "path/to/spec", + "--genesis-builder", + "runtime", + "--genesis-builder-preset", + "preset", + ]); + Ok(()) + } +} diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs index a507c1d1f548..54a055d4a33f 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -19,8 +19,9 @@ mod command; mod types; mod writer; -use crate::{pallet::types::GenesisBuilderPolicy, shared::HostInfoParams}; +use crate::shared::HostInfoParams; use clap::ValueEnum; +use frame_support::Serialize; use sc_cli::{ WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, DEFAULT_WASM_EXECUTION_METHOD, @@ -53,6 +54,10 @@ pub struct PalletCmd { #[arg(short, long, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))] pub extrinsic: Option, + /// Comma separated list of pallets that should be excluded from the benchmark. + #[arg(long, value_parser, num_args = 1.., value_delimiter = ',')] + pub exclude_pallets: Vec, + /// Run benchmarks for all pallets and extrinsics. /// /// This is equivalent to running `--pallet * --extrinsic *`. @@ -168,7 +173,7 @@ pub struct PalletCmd { pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Optional runtime blob to use instead of the one from the genesis config. - #[arg(long, conflicts_with = "chain")] + #[arg(long, conflicts_with = "chain", required_if_eq("genesis_builder", "runtime"))] pub runtime: Option, /// Do not fail if there are unknown but also unused host functions in the runtime. @@ -177,8 +182,7 @@ pub struct PalletCmd { /// How to construct the genesis state. /// - /// Uses `GenesisBuilderPolicy::Spec` by default and `GenesisBuilderPolicy::Runtime` if - /// `runtime` is set. + /// Uses `GenesisBuilderPolicy::Spec` by default. #[arg(long, value_enum, alias = "genesis-builder-policy")] pub genesis_builder: Option, @@ -261,3 +265,22 @@ pub struct PalletCmd { #[arg(long)] disable_proof_recording: bool, } + +/// How the genesis state for benchmarking should be built. +#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy, Serialize)] +#[clap(rename_all = "kebab-case")] +pub enum GenesisBuilderPolicy { + /// Do not provide any genesis state. + /// + /// Benchmarks are advised to function with this, since they should setup their own required + /// state. However, to keep backwards compatibility, this is not the default. + None, + /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. + /// This will use the `development` preset by default. + Runtime, + /// Use the runtime from the Spec file to build the genesis state. + SpecRuntime, + /// Use the spec file to build the genesis state. This fails when there is no spec. + #[value(alias = "spec")] + SpecGenesis, +} diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs b/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs index 1e5e294acba2..a044049a0d61 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -22,7 +22,11 @@ use core::marker::PhantomData; /// Weight functions for `{{pallet}}`. pub struct WeightInfo(PhantomData); +{{#if (eq pallet "frame_system_extensions")}} +impl frame_system::ExtensionsWeightInfo for WeightInfo { +{{else}} impl {{pallet}}::WeightInfo for WeightInfo { +{{/if}} {{#each benchmarks as |benchmark|}} {{#each benchmark.comments as |comment|}} /// {{comment}} diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs index ce37be455e8a..4cfcc60907d9 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/types.rs @@ -18,33 +18,15 @@ //! Various types used by this crate. use sc_cli::Result; -use sp_core::traits::RuntimeCode; +use sp_core::traits::{RuntimeCode, WrappedRuntimeCode}; use sp_runtime::traits::Hash; -/// How the genesis state for benchmarking should be build. -#[derive(clap::ValueEnum, Debug, Eq, PartialEq, Clone, Copy)] -#[clap(rename_all = "kebab-case")] -pub enum GenesisBuilderPolicy { - /// Do not provide any genesis state. - /// - /// Benchmarks are advised to function with this, since they should setup their own required - /// state. However, to keep backwards compatibility, this is not the default. - None, - /// Let the runtime build the genesis state through its `BuildGenesisConfig` runtime API. - Runtime, - // Use the runtime from the Spec file to build the genesis state. - SpecRuntime, - /// Use the spec file to build the genesis state. This fails when there is no spec. - SpecGenesis, - /// Same as `SpecGenesis` - only here for backwards compatibility. - Spec, -} - /// A runtime blob that was either fetched from genesis storage or loaded from a file. // NOTE: This enum is only needed for the annoying lifetime bounds on `RuntimeCode`. Otherwise we // could just directly return the blob. -pub struct FetchedCode<'a, B, H> { - pub state: sp_state_machine::backend::BackendRuntimeCode<'a, B, H>, +pub enum FetchedCode<'a, B, H> { + FromGenesis { state: sp_state_machine::backend::BackendRuntimeCode<'a, B, H> }, + FromFile { wrapped_code: WrappedRuntimeCode<'a>, heap_pages: Option, hash: Vec }, } impl<'a, B, H> FetchedCode<'a, B, H> @@ -54,7 +36,14 @@ where { /// The runtime blob. pub fn code(&'a self) -> Result> { - self.state.runtime_code().map_err(Into::into) + match self { + Self::FromGenesis { state } => state.runtime_code().map_err(Into::into), + Self::FromFile { wrapped_code, heap_pages, hash } => Ok(RuntimeCode { + code_fetcher: wrapped_code, + heap_pages: *heap_pages, + hash: hash.clone(), + }), + } } } diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs index 34f31734da67..28918dd4e6a3 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -484,9 +484,6 @@ pub(crate) fn write_results( benchmarks: results.clone(), }; - let file_path = fs::canonicalize(&file_path).map_err(|e| { - format!("Could not get absolute path for: {:?}. Error: {:?}", &file_path, e) - })?; let mut output_file = fs::File::create(&file_path).map_err(|e| { format!("Could not write weight file to: {:?}. Error: {:?}", &file_path, e) })?; diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs new file mode 100644 index 000000000000..1ca3e36d25ad --- /dev/null +++ b/substrate/utils/frame/benchmarking-cli/src/shared/genesis_state.rs @@ -0,0 +1,141 @@ +// 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 crate::overhead::command::ParachainExtension; +use sc_chain_spec::{ChainSpec, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; +use sc_cli::Result; +use serde_json::Value; +use sp_storage::{well_known_keys::CODE, Storage}; +use sp_wasm_interface::HostFunctions; +use std::{borrow::Cow, path::PathBuf}; + +/// When the runtime could not build the genesis storage. +const ERROR_CANNOT_BUILD_GENESIS: &str = "The runtime returned \ +an error when trying to build the genesis storage. Please ensure that all pallets \ +define a genesis config that can be built. This can be tested with: \ +https://github.com/paritytech/polkadot-sdk/pull/3412"; + +/// Warn when using the chain spec to generate the genesis state. +pub const WARN_SPEC_GENESIS_CTOR: &'static str = "Using the chain spec instead of the runtime to \ +generate the genesis state is deprecated. Please remove the `--chain`/`--dev`/`--local` argument, \ +point `--runtime` to your runtime blob and set `--genesis-builder=runtime`. This warning may \ +become a hard error any time after December 2024."; + +/// Defines how the chain specification shall be used to build the genesis storage. +pub enum SpecGenesisSource { + /// Use preset provided by the runtime embedded in the chain specification. + Runtime(String), + /// Use provided chain-specification JSON file. + SpecJson, + /// Use default storage. + None, +} + +/// Defines how the genesis storage shall be built. +pub enum GenesisStateHandler { + ChainSpec(Box, SpecGenesisSource), + Runtime(Vec, Option), +} + +impl GenesisStateHandler { + /// Populate the genesis storage. + /// + /// If the raw storage is derived from a named genesis preset, `json_patcher` is can be used to + /// inject values into the preset. + pub fn build_storage( + &self, + json_patcher: Option Value + 'static>>, + ) -> Result { + match self { + GenesisStateHandler::ChainSpec(chain_spec, source) => match source { + SpecGenesisSource::Runtime(preset) => { + let mut storage = chain_spec.build_storage()?; + let code_bytes = storage + .top + .remove(CODE) + .ok_or("chain spec genesis does not contain code")?; + genesis_from_code::(code_bytes.as_slice(), preset, json_patcher) + }, + SpecGenesisSource::SpecJson => chain_spec + .build_storage() + .map_err(|e| format!("{ERROR_CANNOT_BUILD_GENESIS}\nError: {e}").into()), + SpecGenesisSource::None => Ok(Storage::default()), + }, + GenesisStateHandler::Runtime(code_bytes, Some(preset)) => + genesis_from_code::(code_bytes.as_slice(), preset, json_patcher), + GenesisStateHandler::Runtime(_, None) => Ok(Storage::default()), + } + } + + /// Get the runtime code blob. + pub fn get_code_bytes(&self) -> Result> { + match self { + GenesisStateHandler::ChainSpec(chain_spec, _) => { + let mut storage = chain_spec.build_storage()?; + storage + .top + .remove(CODE) + .map(|code| Cow::from(code)) + .ok_or("chain spec genesis does not contain code".into()) + }, + GenesisStateHandler::Runtime(code_bytes, _) => Ok(code_bytes.into()), + } + } +} + +pub fn chain_spec_from_path( + chain: PathBuf, +) -> Result<(Box, Option)> { + let spec = GenericChainSpec::::from_json_file(chain) + .map_err(|e| format!("Unable to load chain spec: {:?}", e))?; + + let para_id_from_chain_spec = spec.extensions().para_id; + Ok((Box::new(spec), para_id_from_chain_spec)) +} + +fn genesis_from_code( + code: &[u8], + genesis_builder_preset: &String, + storage_patcher: Option Value>>, +) -> Result { + let genesis_config_caller = GenesisConfigBuilderRuntimeCaller::<( + sp_io::SubstrateHostFunctions, + frame_benchmarking::benchmarking::HostFunctions, + EHF, + )>::new(code); + + let mut preset_json = genesis_config_caller.get_named_preset(Some(genesis_builder_preset))?; + if let Some(patcher) = storage_patcher { + preset_json = patcher(preset_json); + } + + let mut storage = + genesis_config_caller.get_storage_for_patch(preset_json).inspect_err(|e| { + let presets = genesis_config_caller.preset_names().unwrap_or_default(); + log::error!( + "Please pick one of the available presets with \ + `--genesis-builder-preset=`. Available presets ({}): {:?}. Error: {:?}", + presets.len(), + presets, + e + ); + })?; + + storage.top.insert(CODE.into(), code.into()); + + Ok(storage) +} diff --git a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs index f8aa49b867f7..6c9c74e0312c 100644 --- a/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -17,6 +17,7 @@ //! Code that is shared among all benchmarking sub-commands. +pub mod genesis_state; pub mod record; pub mod stats; pub mod weight_params; diff --git a/substrate/utils/frame/omni-bencher/Cargo.toml b/substrate/utils/frame/omni-bencher/Cargo.toml index e2ffca8b4714..345a7288d45b 100644 --- a/substrate/utils/frame/omni-bencher/Cargo.toml +++ b/substrate/utils/frame/omni-bencher/Cargo.toml @@ -20,3 +20,11 @@ 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 } diff --git a/substrate/utils/frame/omni-bencher/src/command.rs b/substrate/utils/frame/omni-bencher/src/command.rs index 19177ed549b7..f5796d05e339 100644 --- a/substrate/utils/frame/omni-bencher/src/command.rs +++ b/substrate/utils/frame/omni-bencher/src/command.rs @@ -16,7 +16,7 @@ // limitations under the License. use clap::Parser; -use frame_benchmarking_cli::BenchmarkCmd; +use frame_benchmarking_cli::{BenchmarkCmd, OpaqueBlock}; use sc_cli::Result; use sp_runtime::traits::BlakeTwo256; @@ -129,27 +129,28 @@ impl Command { } } } - impl V1SubCommand { pub fn run(self) -> Result<()> { - let pallet = match self { + match self { V1SubCommand::Benchmark(V1BenchmarkCommand { sub }) => match sub { - BenchmarkCmd::Pallet(pallet) => pallet, + BenchmarkCmd::Pallet(pallet) => { + if let Some(spec) = pallet.shared_params.chain { + return Err(format!( + "Chain specs are not supported. Please remove `--chain={spec}` and use \ + `--runtime=` instead" + ) + .into()); + } + + pallet.run_with_spec::(None) + }, + BenchmarkCmd::Overhead(overhead_cmd) => + overhead_cmd.run_with_default_builder_and_spec::(None), _ => return Err( - "Only the `v1 benchmark pallet` command is currently supported".into() + "Only the `v1 benchmark pallet` and `v1 benchmark overhead` command is currently supported".into() ), }, - }; - - if let Some(spec) = pallet.shared_params.chain { - return Err(format!( - "Chain specs are not supported. Please remove `--chain={spec}` and use \ - `--runtime=` instead" - ) - .into()) } - - pallet.run_with_spec::(None) } } diff --git a/substrate/utils/frame/omni-bencher/src/main.rs b/substrate/utils/frame/omni-bencher/src/main.rs index ef3450add8e4..7d8aa891dc4a 100644 --- a/substrate/utils/frame/omni-bencher/src/main.rs +++ b/substrate/utils/frame/omni-bencher/src/main.rs @@ -31,7 +31,16 @@ fn main() -> Result<()> { /// Setup logging with `info` as default level. Can be set via `RUST_LOG` env. fn setup_logger() { - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + // Disable these log targets because they are spammy. + let unwanted_targets = + &["cranelift_codegen", "wasm_cranelift", "wasmtime_jit", "wasmtime_cranelift", "wasm_jit"]; + + let mut env_filter = + EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + + for target in unwanted_targets { + env_filter = env_filter.add_directive(format!("{}=off", target).parse().unwrap()); + } tracing_subscriber::fmt() .with_env_filter(env_filter) diff --git a/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs new file mode 100644 index 000000000000..fb1687639639 --- /dev/null +++ b/substrate/utils/frame/omni-bencher/tests/benchmark_works.rs @@ -0,0 +1,167 @@ +// 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 assert_cmd::cargo::cargo_bin; +use std::{ + fs, + path::{Path, PathBuf}, + process::{Command, ExitStatus}, +}; + +#[test] +fn benchmark_overhead_runtime_works() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let base_path = tmp_dir.path(); + let wasm = cumulus_test_runtime::WASM_BINARY.ok_or("WASM binary not available".to_string())?; + let runtime_path = base_path.join("runtime.wasm"); + let _ = + fs::write(&runtime_path, wasm).map_err(|e| format!("Unable to write runtime file: {}", e)); + + // Invoke `benchmark overhead` with all options to make sure that they are valid. + let status = std::process::Command::new(cargo_bin("frame-omni-bencher")) + .args(["v1", "benchmark", "overhead", "--runtime", runtime_path.to_str().unwrap()]) + .arg("-d") + .arg(base_path) + .arg("--weight-path") + .arg(base_path) + .args(["--warmup", "5", "--repeat", "5"]) + // Exotic para id to see that we are actually patching. + .args(["--para-id", "666"]) + .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + // Only put 5 extrinsics into the block otherwise it takes forever to build it + // especially for a non-release builds. + .args(["--max-ext-per-block", "5"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, base_path) +} +#[test] +fn benchmark_overhead_chain_spec_works() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), false)?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec-runtime"]) + .args(["--para-id", "666"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, &base_path) +} + +#[test] +fn benchmark_overhead_chain_spec_works_plain_spec() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), false)?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec"]) + .args(["--para-id", "100"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, &base_path) +} + +#[test] +fn benchmark_overhead_chain_spec_works_raw() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), true)?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec"]) + .args(["--para-id", "100"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + assert_benchmark_success(status, &base_path) +} + +#[test] +fn benchmark_overhead_chain_spec_fails_wrong_para_id() -> std::result::Result<(), String> { + let tmp_dir = tempfile::tempdir().expect("Should be able to create tmp dir."); + let (base_path, chain_spec_path) = setup_chain_spec(tmp_dir.path(), false)?; + + let status = create_benchmark_spec_command(&base_path, &chain_spec_path) + .args(["--genesis-builder-policy", "spec"]) + .args(["--para-id", "666"]) + .status() + .map_err(|e| format!("command failed: {:?}", e))?; + + if status.success() { + return Err("Command should have failed!".into()) + } + + // Weight files should not have been created + assert!(!base_path.join("block_weights.rs").exists()); + assert!(!base_path.join("extrinsic_weights.rs").exists()); + Ok(()) +} + +/// Sets up a temporary directory and creates a chain spec file +fn setup_chain_spec(tmp_dir: &Path, raw: bool) -> Result<(PathBuf, PathBuf), String> { + let base_path = tmp_dir.to_path_buf(); + let chain_spec_path = base_path.join("chain_spec.json"); + + let wasm = cumulus_test_runtime::WASM_BINARY.ok_or("WASM binary not available".to_string())?; + + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "UNIT".into()); + properties.insert("tokenDecimals".into(), 12.into()); + + let chain_spec = sc_chain_spec::GenericChainSpec::<()>::builder(wasm, Default::default()) + .with_name("some-chain") + .with_id("some-id") + .with_properties(properties) + .with_chain_type(sc_chain_spec::ChainType::Development) + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) + .build(); + + let json = chain_spec.as_json(raw).unwrap(); + fs::write(&chain_spec_path, json) + .map_err(|e| format!("Unable to write chain-spec file: {}", e))?; + + Ok((base_path, chain_spec_path)) +} + +/// Creates a Command for the benchmark with common arguments +fn create_benchmark_spec_command(base_path: &Path, chain_spec_path: &Path) -> Command { + let mut cmd = Command::new(cargo_bin("frame-omni-bencher")); + cmd.args(["v1", "benchmark", "overhead", "--chain", chain_spec_path.to_str().unwrap()]) + .arg("-d") + .arg(base_path) + .arg("--weight-path") + .arg(base_path) + .args(["--warmup", "5", "--repeat", "5"]) + .args(["--add", "100", "--mul", "1.2", "--metric", "p75"]) + // Only put 5 extrinsics into the block otherwise it takes forever to build it + .args(["--max-ext-per-block", "5"]); + cmd +} + +/// Checks if the benchmark completed successfully and created weight files +fn assert_benchmark_success(status: ExitStatus, base_path: &Path) -> Result<(), String> { + if !status.success() { + return Err("Command failed".into()) + } + + // Weight files have been created + assert!(base_path.join("block_weights.rs").exists()); + assert!(base_path.join("extrinsic_weights.rs").exists()); + Ok(()) +} diff --git a/substrate/utils/frame/remote-externalities/src/lib.rs b/substrate/utils/frame/remote-externalities/src/lib.rs index 955e79008c8c..75a2ac2aef41 100644 --- a/substrate/utils/frame/remote-externalities/src/lib.rs +++ b/substrate/utils/frame/remote-externalities/src/lib.rs @@ -1239,8 +1239,9 @@ where #[cfg(test)] mod test_prelude { pub(crate) use super::*; - pub(crate) use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; - pub(crate) type Block = RawBlock>; + pub(crate) use sp_runtime::testing::{Block as RawBlock, MockCallU64}; + pub(crate) type UncheckedXt = sp_runtime::testing::TestXt; + pub(crate) type Block = RawBlock; pub(crate) fn init_logger() { sp_tracing::try_init_simple(); diff --git a/substrate/utils/frame/rpc/client/src/lib.rs b/substrate/utils/frame/rpc/client/src/lib.rs index 221f260b1566..0aecad553053 100644 --- a/substrate/utils/frame/rpc/client/src/lib.rs +++ b/substrate/utils/frame/rpc/client/src/lib.rs @@ -199,11 +199,12 @@ where #[cfg(test)] mod tests { use super::*; - use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header, H256}; + use sp_runtime::testing::{Block as TBlock, Header, MockCallU64, TestXt, H256}; use std::sync::Arc; use tokio::sync::Mutex; - type Block = TBlock>; + type UncheckedXt = TestXt; + type Block = TBlock; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/utils/frame/rpc/system/src/lib.rs b/substrate/utils/frame/rpc/system/src/lib.rs index 9fcaa53a35d8..824c871a3562 100644 --- a/substrate/utils/frame/rpc/system/src/lib.rs +++ b/substrate/utils/frame/rpc/system/src/lib.rs @@ -245,8 +245,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); let source = sp_runtime::transaction_validity::TransactionSource::External; let new_transaction = |nonce: u64| { @@ -281,8 +286,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); let accounts = System::new(client, pool); @@ -300,8 +310,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); let accounts = System::new(client, pool); @@ -331,8 +346,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let pool = - BasicPool::new_full(Default::default(), true.into(), None, spawner, client.clone()); + let pool = Arc::from(BasicPool::new_full( + Default::default(), + true.into(), + None, + spawner, + client.clone(), + )); let accounts = System::new(client, pool); 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 460640bcd8e4..5edac2e6650f 100644 --- a/substrate/utils/prometheus/src/lib.rs +++ b/substrate/utils/prometheus/src/lib.rs @@ -27,8 +27,8 @@ pub use prometheus::{ AtomicF64 as F64, AtomicI64 as I64, AtomicU64 as U64, GenericCounter as Counter, GenericCounterVec as CounterVec, GenericGauge as Gauge, GenericGaugeVec as GaugeVec, }, - exponential_buckets, Error as PrometheusError, Histogram, HistogramOpts, HistogramVec, Opts, - Registry, + exponential_buckets, histogram_opts, linear_buckets, Error as PrometheusError, Histogram, + HistogramOpts, HistogramVec, Opts, Registry, }; pub use sourced::{MetricSource, SourcedCounter, SourcedGauge, SourcedMetric}; @@ -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/src/builder.rs b/substrate/utils/wasm-builder/src/builder.rs index eb761a103d62..a40aafe1d812 100644 --- a/substrate/utils/wasm-builder/src/builder.rs +++ b/substrate/utils/wasm-builder/src/builder.rs @@ -303,7 +303,8 @@ fn provide_dummy_wasm_binary_if_not_exist(file_path: &Path) { if !file_path.exists() { crate::write_file_if_changed( file_path, - "pub const WASM_BINARY: Option<&[u8]> = None;\ + "pub const WASM_BINARY_PATH: Option<&str> = None;\ + pub const WASM_BINARY: Option<&[u8]> = None;\ pub const WASM_BINARY_BLOATY: Option<&[u8]> = None;", ); } @@ -378,9 +379,11 @@ fn build_project( file_name, format!( r#" + pub const WASM_BINARY_PATH: Option<&str> = Some("{wasm_binary_path}"); pub const WASM_BINARY: Option<&[u8]> = Some(include_bytes!("{wasm_binary}")); pub const WASM_BINARY_BLOATY: Option<&[u8]> = Some(include_bytes!("{wasm_binary_bloaty}")); "#, + wasm_binary_path = wasm_binary, wasm_binary = wasm_binary, wasm_binary_bloaty = wasm_binary_bloaty, ), diff --git a/substrate/utils/wasm-builder/src/lib.rs b/substrate/utils/wasm-builder/src/lib.rs index e3f2ff5cd733..420ecd63e1dc 100644 --- a/substrate/utils/wasm-builder/src/lib.rs +++ b/substrate/utils/wasm-builder/src/lib.rs @@ -48,6 +48,8 @@ //! This will include the generated Wasm binary as two constants `WASM_BINARY` and //! `WASM_BINARY_BLOATY`. The former is a compact Wasm binary and the latter is the Wasm binary as //! being generated by the compiler. Both variables have `Option<&'static [u8]>` as type. +//! Additionally it will create the `WASM_BINARY_PATH` which is the path to the WASM blob on the +//! filesystem. //! //! ### Feature //! diff --git a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml index e388af7c94f8..2f0fc7b9fe3b 100644 --- a/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml +++ b/substrate/zombienet/0002-validators-warp-sync/test-validators-warp-sync.toml @@ -11,12 +11,12 @@ chain_spec_path = "chain-spec.json" [[relaychain.nodes]] name = "alice" validator = true - args = ["--sync warp"] + args = ["--log=beefy=debug", "--sync warp"] [[relaychain.nodes]] name = "bob" validator = true - args = ["--sync warp"] + args = ["--log=beefy=debug", "--sync warp"] # we need at least 3 nodes for warp sync [[relaychain.nodes]] 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 b68bce508c00..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 @@ -31,13 +31,14 @@ bob: log line matches "Block history download is complete" within 120 seconds alice: reports block height is at least {{DB_BLOCK_HEIGHT}} within 10 seconds bob: reports block height is at least {{DB_BLOCK_HEIGHT}} within 10 seconds -alice: reports substrate_beefy_best_block is at least {{DB_BLOCK_HEIGHT}} within 180 seconds -bob: reports substrate_beefy_best_block is at least {{DB_BLOCK_HEIGHT}} within 180 seconds - -alice: reports substrate_beefy_best_block is greater than {{DB_BLOCK_HEIGHT}} within 180 seconds -bob: reports substrate_beefy_best_block is greater than {{DB_BLOCK_HEIGHT}} within 180 seconds - -alice: count of log lines containing "error" is 0 within 10 seconds +# In the worst case scenario, the validators should vote on 1 mandatory block each 6 seconds. And 1 era = 200 blocks. +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 + +# 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/Dockerfile b/templates/minimal/Dockerfile index 0c59192208fe..422f7f726a7e 100644 --- a/templates/minimal/Dockerfile +++ b/templates/minimal/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /polkadot COPY . /polkadot RUN cargo fetch -RUN cargo build --locked --release +RUN cargo build --workspace --locked --release FROM docker.io/parity/base-bin:latest diff --git a/templates/minimal/README.md b/templates/minimal/README.md index fe1317a033c7..cf43d71d8849 100644 --- a/templates/minimal/README.md +++ b/templates/minimal/README.md @@ -11,30 +11,54 @@ -* 🤏 This template is a minimal (in terms of complexity and the number of components) +## Table of Contents + +- [Intro](#intro) + +- [Template Structure](#template-structure) + +- [Getting Started](#getting-started) + +- [Starting a Minimal Template Chain](#starting-a-minimal-template-chain) + + - [Omni Node](#omni-node) + - [Minimal Template Node](#minimal-template-node) + - [Zombienet with Omni Node](#zombienet-with-omni-node) + - [Zombienet with Minimal Template Node](#zombienet-with-minimal-template-node) + - [Connect with the Polkadot-JS Apps Front-End](#connect-with-the-polkadot-js-apps-front-end) + - [Takeaways](#takeaways) + +- [Contributing](#contributing) + +- [Getting Help](#getting-help) + +## Intro + +- 🤏 This template is a minimal (in terms of complexity and the number of components) template for building a blockchain node. -* 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets +- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets such as a [Balances pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_balances/index.html). -* 👤 The template has no consensus configured - it is best for experimenting with a single node network. +- 👤 The template has no consensus configured - it is best for experimenting with a single node network. ## Template Structure A Polkadot SDK based project such as this one consists of: -* 💿 a [Node](./node/README.md) - the binary application. -* 🧮 the [Runtime](./runtime/README.md) - the core logic of the blockchain. -* 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed. +- 🧮 the [Runtime](./runtime/README.md) - the core logic of the blockchain. +- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed. +- 💿 a [Node](./node/README.md) - the binary application (which is not part of the cargo default-members list and is not +compiled unless building the entire workspace). ## Getting Started -* 🦀 The template is using the Rust language. +- 🦀 The template is using the Rust language. -* 👉 Check the +- 👉 Check the [Rust installation instructions](https://www.rust-lang.org/tools/install) for your system. -* 🛠️ Depending on your operating system and Rust version, there might be additional +- 🛠️ Depending on your operating system and Rust version, there might be additional packages required to compile this template - please take note of the Rust compiler output. Fetch minimal template code: @@ -45,65 +69,152 @@ git clone https://github.com/paritytech/polkadot-sdk-minimal-template.git minima cd minimal-template ``` -### Build +## Starting a Minimal Template Chain + +### Omni Node + +[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can +be used to run the minimal template's runtime. `polkadot-omni-node` binary crate usage is described at a high-level +[on crates.io](https://crates.io/crates/polkadot-omni-node). + +#### Install `polkadot-omni-node` + +Please see installation section on [crates.io/omni-node](https://crates.io/crates/polkadot-omni-node). + +#### Build `minimal-template-runtime` + +```sh +cargo build -p minimal-template-runtime --release +``` + +#### Install `staging-chain-spec-builder` -🔨 Use the following command to build the node without launching it: +Please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder). + +#### Use chain-spec-builder to generate the chain_spec.json file ```sh -cargo build --release +chain-spec-builder create --relay-chain "dev" --para-id 1000 --runtime \ + target/release/wbuild/minimal-template-runtime/minimal_template_runtime.wasm named-preset development ``` -🐳 Alternatively, build the docker image: +**Note**: the `relay-chain` and `para-id` flags are extra bits of information required to +configure the node for the case of representing a parachain that is connected to a relay chain. +They are not relevant to minimal template business logic, but they are mandatory information for +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. + +```sh +polkadot-omni-node --chain --dev-block-time 3000 --tmp +``` + +### Minimal Template Node + +#### Build both node & runtime + +```sh +cargo build --workspace --release +``` + +🐳 Alternatively, build the docker image which builds all the workspace members, +and has as entry point the node binary: ```sh docker build . -t polkadot-sdk-minimal-template ``` -### Single-Node Development Chain +#### Start the `minimal-template-node` -👤 The following command starts a single-node development chain: +The `minimal-template-node` has dependency on the `minimal-template-runtime`. It will use +the `minimal_template_runtime::WASM_BINARY` constant (which holds the WASM blob as a byte +array) for chain spec building, while starting. This is in contrast to Omni Node which doesn't +depend on a specific runtime, but asks for the chain spec at startup. ```sh -./target/release/minimal-template-node --dev + --tmp --consensus manual-seal-3000 +# or via docker +docker run --rm polkadot-sdk-minimal-template +``` + +### Zombienet with Omni Node + +#### Install `zombienet` + +We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), +and `zombienet-omni-node.toml` contains the network specification we want to start. + +#### Update `zombienet-omni-node.toml` with a valid chain spec path + +Before starting the network with zombienet we must update the network specification +with a valid chain spec path. If we need to generate one, we can look up at the previous +section for chain spec creation [here](#use-chain-spec-builder-to-generate-the-chain_specjson-file). -# docker version: -docker run --rm polkadot-sdk-minimal-template --dev +Then make the changes in the network specification like so: + +```toml +# ... +chain = "dev" +chain_spec_path = "" +default_args = ["--dev-block-time 3000"] +# .. +``` + +#### Start the network + +```sh +zombienet --provider native spawn zombienet-omni-node.toml ``` -Development chains: +### Zombienet with `minimal-template-node` -* 🧹 Do not persist the state. -* 💰 Are pre-configured with a genesis state that includes several pre-funded development accounts. -* 🧑‍⚖️ One development account (`ALICE`) is used as `sudo` accounts. +For this one we just need to have `zombienet` installed and run: + +```sh +zombienet --provider native spawn zombienet-multi-node.toml +``` ### Connect with the Polkadot-JS Apps Front-End -* 🌐 You can interact with your local node using the +- 🌐 You can interact with your local node using the hosted version of the [Polkadot/Substrate Portal](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944). -* 🪐 A hosted version is also +- 🪐 A hosted version is also available on [IPFS](https://dotapps.io/). -* 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the +- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the [`polkadot-js/apps`](https://github.com/polkadot-js/apps) repository. +### Takeaways + +Previously minimal template's development chains: + +- ❌ Started in a multi-node setup will produce forks because minimal lacks consensus. +- 🧹 Do not persist the state. +- 💰 Are pre-configured with a genesis state that includes several pre-funded development accounts. +- 🧑‍⚖️ One development account (`ALICE`) is used as `sudo` accounts. + ## Contributing -* 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk). +- 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk). -* ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/minimal). +- ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/minimal). -* 😇 Please refer to the monorepo's +- 😇 Please refer to the monorepo's [contribution guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and [Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md). ## Getting Help -* 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point. +- 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point. -* 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are +- 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are the Polkadot SDK documentation resources. -* 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and +- 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and [Substrate StackExchange](https://substrate.stackexchange.com/). diff --git a/templates/minimal/node/src/cli.rs b/templates/minimal/node/src/cli.rs index 54107df75a36..f349f8c8da04 100644 --- a/templates/minimal/node/src/cli.rs +++ b/templates/minimal/node/src/cli.rs @@ -21,6 +21,7 @@ use polkadot_sdk::{sc_cli::RunCmd, *}; pub enum Consensus { ManualSeal(u64), InstantSeal, + None, } impl std::str::FromStr for Consensus { @@ -31,6 +32,8 @@ impl std::str::FromStr for Consensus { Consensus::InstantSeal } else if let Some(block_time) = s.strip_prefix("manual-seal-") { Consensus::ManualSeal(block_time.parse().map_err(|_| "invalid block time")?) + } else if s.to_lowercase() == "none" { + Consensus::None } else { return Err("incorrect consensus identifier".into()); }) diff --git a/templates/minimal/node/src/service.rs b/templates/minimal/node/src/service.rs index 08cd345f1e3e..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, @@ -46,7 +44,7 @@ pub type Service = sc_service::PartialComponents< FullBackend, FullSelectChain, sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, Option, >; @@ -79,12 +77,15 @@ pub fn new_partial(config: &Configuration) -> Result { let select_chain = sc_consensus::LongestChain::new(backend.clone()); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let import_queue = sc_consensus_manual_seal::import_queue( @@ -121,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, @@ -133,34 +134,22 @@ 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, })?; if config.offchain_worker.enabled { - task_manager.spawn_handle().spawn( - "offchain-workers-runner", - "offchain-worker", + let offchain_workers = sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { runtime_api_provider: client.clone(), is_validator: config.role.is_authority(), @@ -172,9 +161,11 @@ pub fn new_full::Ha network_provider: Arc::new(network.clone()), enable_http_requests: true, custom_extensions: |_| vec![], - }) - .run(client.clone(), task_manager.spawn_handle()) - .boxed(), + })?; + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-worker", + offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(), ); } @@ -270,8 +261,8 @@ pub fn new_full::Ha authorship_future, ); }, + _ => {}, } - network_starter.start_network(); Ok(task_manager) } diff --git a/templates/minimal/pallets/template/src/lib.rs b/templates/minimal/pallets/template/src/lib.rs index b8a8614932a6..722b606079f9 100644 --- a/templates/minimal/pallets/template/src/lib.rs +++ b/templates/minimal/pallets/template/src/lib.rs @@ -5,6 +5,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use frame::prelude::*; use polkadot_sdk::polkadot_sdk_frame as frame; // Re-export all pallet parts, this is needed to properly import the pallet into the runtime. @@ -19,4 +20,7 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); + + #[pallet::storage] + pub type Value = StorageValue; } diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index 74a09b9396e5..b803c74539ef 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -13,7 +13,6 @@ publish = false codec = { workspace = true } scale-info = { workspace = true } polkadot-sdk = { workspace = true, features = [ - "experimental", "pallet-balances", "pallet-sudo", "pallet-timestamp", diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 7379e33b6b3e..7b8449f2abe4 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -30,7 +30,7 @@ use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use polkadot_sdk::{ polkadot_sdk_frame::{ self as frame, - prelude::*, + deps::sp_genesis_builder, runtime::{apis, prelude::*}, }, *, @@ -38,37 +38,33 @@ use polkadot_sdk::{ /// Provides getters for genesis configuration presets. pub mod genesis_config_presets { + use super::*; use crate::{ interface::{Balance, MinimumBalance}, - sp_genesis_builder::PresetId, sp_keyring::AccountKeyring, BalancesConfig, RuntimeGenesisConfig, SudoConfig, }; use alloc::{vec, vec::Vec}; - use polkadot_sdk::{sp_core::Get, sp_genesis_builder}; use serde_json::Value; /// 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() .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.") + }) } /// 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( @@ -87,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, @@ -103,8 +99,8 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -/// The signed extensions that are added to the runtime. -type SignedExtra = ( +/// The transaction extensions that are added to the runtime. +type TxExtension = ( // Checks that the sender is not the zero address. frame_system::CheckNonZeroSender, // Checks that the runtime version is correct. @@ -207,7 +203,7 @@ impl pallet_transaction_payment::Config for Runtime { // Implements the types required for the template pallet. impl pallet_minimal_template::Config for Runtime {} -type Block = frame::runtime::types_common::BlockOf; +type Block = frame::runtime::types_common::BlockOf; type Header = HeaderFor; type RuntimeExecutive = @@ -314,16 +310,16 @@ impl_runtime_apis! { } } - impl sp_genesis_builder::GenesisBuilder for Runtime { + impl apis::GenesisBuilder for Runtime { fn build_state(config: Vec) -> sp_genesis_builder::Result { build_state::(config) } - fn get_preset(id: &Option) -> Option> { + fn get_preset(id: &Option) -> Option> { get_preset::(id, self::genesis_config_presets::get_preset) } - fn preset_names() -> Vec { + fn preset_names() -> Vec { self::genesis_config_presets::preset_names() } } diff --git a/templates/minimal/zombienet-omni-node.toml b/templates/minimal/zombienet-omni-node.toml new file mode 100644 index 000000000000..33b0fceba68c --- /dev/null +++ b/templates/minimal/zombienet-omni-node.toml @@ -0,0 +1,9 @@ +[relaychain] +default_command = "polkadot-omni-node" +chain = "dev" +chain_spec_path = "" +default_args = ["--dev-block-time 3000"] + +[[relaychain.nodes]] +name = "alice" +ws_port = 9944 diff --git a/templates/minimal/zombienet.toml b/templates/minimal/zombienet.toml new file mode 100644 index 000000000000..89df054bf652 --- /dev/null +++ b/templates/minimal/zombienet.toml @@ -0,0 +1,30 @@ +# The setup bellow allows only one node to produce +# blocks and the rest will follow. + +[relaychain] +chain = "dev" +default_command = "minimal-template-node" + +[[relaychain.nodes]] +name = "alice" +args = ["--consensus manual-seal-3000"] +validator = true +ws_port = 9944 + +[[relaychain.nodes]] +name = "bob" +args = ["--consensus None"] +validator = true +ws_port = 9955 + +[[relaychain.nodes]] +name = "charlie" +args = ["--consensus None"] +validator = true +ws_port = 9966 + +[[relaychain.nodes]] +name = "dave" +args = ["--consensus None"] +validator = true +ws_port = 9977 diff --git a/templates/parachain/Dockerfile b/templates/parachain/Dockerfile index 72a8f19fe79a..da1353d5fb9c 100644 --- a/templates/parachain/Dockerfile +++ b/templates/parachain/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /polkadot COPY . /polkadot RUN cargo fetch -RUN cargo build --locked --release +RUN cargo build --workspace --locked --release FROM docker.io/parity/base-bin:latest diff --git a/templates/parachain/README.md b/templates/parachain/README.md index 3de85cbeb4dc..65a6979041f2 100644 --- a/templates/parachain/README.md +++ b/templates/parachain/README.md @@ -11,32 +11,55 @@ -* ⏫ This template provides a starting point to build a [parachain](https://wiki.polkadot.network/docs/learn-parachains). +## Table of Contents -* ☁️ It is based on the +- [Intro](#intro) + +- [Template Structure](#template-structure) + +- [Getting Started](#getting-started) + +- [Starting a Development Chain](#starting-a-development-chain) + + - [Omni Node](#omni-node-prerequisites) + - [Zombienet setup with Omni Node](#zombienet-setup-with-omni-node) + - [Parachain Template Node](#parachain-template-node) + - [Connect with the Polkadot-JS Apps Front-End](#connect-with-the-polkadot-js-apps-front-end) + - [Takeaways](#takeaways) + +- [Contributing](#contributing) +- [Getting Help](#getting-help) + +## Intro + +- ⏫ This template provides a starting point to build a [parachain](https://wiki.polkadot.network/docs/learn-parachains). + +- ☁️ It is based on the [Cumulus](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/cumulus/index.html) framework. -* 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets +- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets such as a [Balances pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_balances/index.html). -* 👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains) +- 👉 Learn more about parachains [here](https://wiki.polkadot.network/docs/learn-parachains) ## Template Structure A Polkadot SDK based project such as this one consists of: -* 💿 a [Node](./node/README.md) - the binary application. -* 🧮 the [Runtime](./runtime/README.md) - the core logic of the parachain. -* 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed. +- 🧮 the [Runtime](./runtime/README.md) - the core logic of the parachain. +- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed. +- 💿 a [Node](./node/README.md) - the binary application, not part of the project default-members list and not compiled unless +building the project with `--workspace` flag, which builds all workspace members, and is an alternative to +[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html). ## Getting Started -* 🦀 The template is using the Rust language. +- 🦀 The template is using the Rust language. -* 👉 Check the +- 👉 Check the [Rust installation instructions](https://www.rust-lang.org/tools/install) for your system. -* 🛠️ Depending on your operating system and Rust version, there might be additional +- 🛠️ Depending on your operating system and Rust version, there might be additional packages required to compile this template - please take note of the Rust compiler output. Fetch parachain template code: @@ -47,90 +70,149 @@ git clone https://github.com/paritytech/polkadot-sdk-parachain-template.git para cd parachain-template ``` -### Build +## Starting a Development Chain + +### Omni Node Prerequisites -🔨 Use the following command to build the node without launching it: +[Omni Node](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can +be used to run the parachain template's runtime. `polkadot-omni-node` binary crate usage is described at a high-level +[on crates.io](https://crates.io/crates/polkadot-omni-node). + +#### Install `polkadot-omni-node` + +Please see the installation section at [`crates.io/omni-node`](https://crates.io/crates/polkadot-omni-node). + +#### Build `parachain-template-runtime` ```sh cargo build --release ``` -🐳 Alternatively, build the docker image: +#### Install `staging-chain-spec-builder` + +Please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder). + +#### Use `chain-spec-builder` to generate the `chain_spec.json` file ```sh -docker build . -t polkadot-sdk-parachain-template +chain-spec-builder create --relay-chain "rococo-local" --para-id 1000 --runtime \ + target/release/wbuild/parachain-template-runtime/parachain_template_runtime.wasm named-preset development ``` -### Local Development Chain +**Note**: the `relay-chain` and `para-id` flags are mandatory information required by +Omni Node, and for parachain template case the value for `para-id` must be set to `1000`, since this +is also the value injected through [ParachainInfo](https://docs.rs/staging-parachain-info/0.17.0/staging_parachain_info/) +pallet into the `parachain-template-runtime`'s storage. The `relay-chain` value is set in accordance +with the relay chain ID where this instantiation of parachain-template will connect to. -🧟 This project uses [Zombienet](https://github.com/paritytech/zombienet) to orchestrate the relaychain and parachain nodes. -You can grab a [released binary](https://github.com/paritytech/zombienet/releases/latest) or use an [npm version](https://www.npmjs.com/package/@zombienet/cli). +#### Run Omni Node -This template produces a parachain node. -You can install it in your environment by running: +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. + +```bash +polkadot-omni-node --chain --tmp --dev-block-time 1000 -```sh -cargo install --path node ``` -You still need a relaychain node - you can download the `polkadot` -(and the accompanying `polkadot-prepare-worker` and `polkadot-execute-worker`) -binaries from [Polkadot SDK releases](https://github.com/paritytech/polkadot-sdk/releases/latest). +However, such a setup is not close to what would run in production, and for that we need to setup a local +relay chain network that will help with the block finalization. In this guide we'll setup a local relay chain +as well. We'll not do it manually, by starting one node at a time, but we'll use [zombienet](https://paritytech.github.io/zombienet/intro.html). + +Follow through the next section for more details on how to do it. -In addition to the installed parachain node, make sure to bring -`zombienet`, `polkadot`, `polkadot-prepare-worker`, and `polkadot-execute-worker` -into `PATH`, for example: +### Zombienet setup with Omni Node + +Assuming we continue from the last step of the previous section, we have a chain spec and we need to setup a relay chain. +We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), and +`zombienet-omni-node.toml` contains the network specification we want to start. + +#### Relay chain prerequisites + +Download the `polkadot` (and the accompanying `polkadot-prepare-worker` and `polkadot-execute-worker`) binaries from +[Polkadot SDK releases](https://github.com/paritytech/polkadot-sdk/releases). Then expose them on `PATH` like so: ```sh -export PATH=":$PATH" +export PATH="$PATH:" ``` -This way, we can conveniently use them in the following steps. +#### Update `zombienet-omni-node.toml` with a valid chain spec path + +```toml +# ... +[[parachains]] +id = 1000 +chain_spec_path = "" +# ... +``` -👥 The following command starts a local development chain, with a single relay chain node and a single parachain collator: +#### Start the network ```sh -zombienet --provider native spawn ./zombienet.toml +zombienet --provider native spawn zombienet-omni-node.toml +``` + +### Parachain Template Node + +As mentioned in the `Template Structure` section, the `node` crate is optionally compiled and it is an alternative +to `Omni Node`. Similarly, it requires setting up a relay chain, and we'll use `zombienet` once more. + +#### Install the `parachain-template-node` -# Alternatively, the npm version: -npx --yes @zombienet/cli --provider native spawn ./zombienet.toml +```sh +cargo install --path node ``` -Development chains: +#### Setup and start the network + +For setup, please consider the instructions for `zombienet` installation [here](https://paritytech.github.io/zombienet/install.html#installation) +and [relay chain prerequisites](#relay-chain-prerequisites). -* 🧹 Do not persist the state. -* 💰 Are preconfigured with a genesis state that includes several prefunded development accounts. -* 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts. +We're left just with starting the network: + +```sh +zombienet --provider native spawn zombienet.toml +``` ### Connect with the Polkadot-JS Apps Front-End -* 🌐 You can interact with your local node using the +- 🌐 You can interact with your local node using the hosted version of the Polkadot/Substrate Portal: [relay chain](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) and [parachain](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9988). -* 🪐 A hosted version is also +- 🪐 A hosted version is also available on [IPFS](https://dotapps.io/). -* 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the +- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the [`polkadot-js/apps`](https://github.com/polkadot-js/apps) repository. +### Takeaways + +Development parachains: + +- 🔗 Connect to relay chains, and we showcased how to connect to a local one. +- 🧹 Do not persist the state. +- 💰 Are preconfigured with a genesis state that includes several prefunded development accounts. +- 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts. + ## Contributing -* 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk). +- 🔄 This template is automatically updated after releases in the main [Polkadot SDK monorepo](https://github.com/paritytech/polkadot-sdk). -* ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/parachain). +- ➡️ Any pull requests should be directed to this [source](https://github.com/paritytech/polkadot-sdk/tree/master/templates/parachain). -* 😇 Please refer to the monorepo's +- 😇 Please refer to the monorepo's [contribution guidelines](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and [Code of Conduct](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md). ## Getting Help -* 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point. +- 🧑‍🏫 To learn about Polkadot in general, [Polkadot.network](https://polkadot.network/) website is a good starting point. -* 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are +- 🧑‍🔧 For technical introduction, [here](https://github.com/paritytech/polkadot-sdk#-documentation) are the Polkadot SDK documentation resources. -* 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and +- 👥 Additionally, there are [GitHub issues](https://github.com/paritytech/polkadot-sdk/issues) and [Substrate StackExchange](https://substrate.stackexchange.com/). diff --git a/templates/parachain/node/Cargo.toml b/templates/parachain/node/Cargo.toml index c0c81d8222a4..ba5f1212b79c 100644 --- a/templates/parachain/node/Cargo.toml +++ b/templates/parachain/node/Cargo.toml @@ -10,9 +10,6 @@ edition.workspace = true publish = false build = "build.rs" -# [[bin]] -# name = "parachain-template-node" - [dependencies] clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } @@ -22,82 +19,31 @@ jsonrpsee = { features = ["server"], workspace = true } futures = { workspace = true } serde_json = { workspace = true, default-features = true } docify = { workspace = true } +color-print = { workspace = true } + +polkadot-sdk = { workspace = true, features = ["node"] } -# Local parachain-template-runtime = { workspace = true } # Substrate -frame-benchmarking = { workspace = true, default-features = true } -frame-benchmarking-cli = { workspace = true, default-features = true } -pallet-transaction-payment-rpc = { 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-offchain = { workspace = true, default-features = true } -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-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-tracing = { workspace = true, default-features = true } -sc-transaction-pool = { workspace = true, default-features = true } -sc-transaction-pool-api = { 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-consensus-aura = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-genesis-builder = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } -substrate-frame-rpc-system = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } -# Polkadot -polkadot-cli = { features = ["rococo-native"], workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -xcm = { workspace = true } - -# Cumulus -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-common = { workspace = true, default-features = true } -cumulus-client-consensus-proposer = { workspace = true, default-features = true } -cumulus-client-service = { workspace = true, default-features = true } -cumulus-primitives-core = { workspace = true, default-features = true } -cumulus-primitives-parachain-inherent = { workspace = true, default-features = true } -cumulus-relay-chain-interface = { workspace = true, default-features = true } -color-print = { workspace = true } - [build-dependencies] -substrate-build-script-utils = { workspace = true, default-features = true } +polkadot-sdk = { workspace = true, features = ["substrate-build-script-utils"] } [features] default = ["std"] std = [ "log/std", "parachain-template-runtime/std", - "xcm/std", + "polkadot-sdk/std", ] runtime-benchmarks = [ - "cumulus-primitives-core/runtime-benchmarks", - "frame-benchmarking-cli/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", "parachain-template-runtime/runtime-benchmarks", - "polkadot-cli/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "sc-service/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "polkadot-sdk/runtime-benchmarks", ] try-runtime = [ "parachain-template-runtime/try-runtime", - "polkadot-cli/try-runtime", - "sp-runtime/try-runtime", + "polkadot-sdk/try-runtime", ] diff --git a/templates/parachain/node/build.rs b/templates/parachain/node/build.rs index e3bfe3116bf2..8ee8f23d8548 100644 --- a/templates/parachain/node/build.rs +++ b/templates/parachain/node/build.rs @@ -1,4 +1,4 @@ -use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; +use polkadot_sdk::substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; fn main() { generate_cargo_keys(); diff --git a/templates/parachain/node/src/chain_spec.rs b/templates/parachain/node/src/chain_spec.rs index af82607bc8e4..55a099dd022b 100644 --- a/templates/parachain/node/src/chain_spec.rs +++ b/templates/parachain/node/src/chain_spec.rs @@ -1,3 +1,5 @@ +use polkadot_sdk::*; + use parachain_template_runtime as runtime; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; diff --git a/templates/parachain/node/src/cli.rs b/templates/parachain/node/src/cli.rs index f008e856d99b..c8bdbc10d751 100644 --- a/templates/parachain/node/src/cli.rs +++ b/templates/parachain/node/src/cli.rs @@ -1,3 +1,4 @@ +use polkadot_sdk::*; use std::path::PathBuf; /// Sub-commands supported by the collator. diff --git a/templates/parachain/node/src/command.rs b/templates/parachain/node/src/command.rs index 6b9deade1271..5d9308aed154 100644 --- a/templates/parachain/node/src/command.rs +++ b/templates/parachain/node/src/command.rs @@ -1,3 +1,5 @@ +use polkadot_sdk::*; + use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; use cumulus_primitives_core::ParaId; use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; @@ -218,13 +220,15 @@ pub fn run() -> Result<()> { runner.run_node_until_exit(|config| async move { let hwbench = (!cli.no_hardware_benchmarks) - .then_some(config.database.path().map(|database_path| { - let _ = std::fs::create_dir_all(database_path); - sc_sysinfo::gather_hwbench( - Some(database_path), - &SUBSTRATE_REFERENCE_HARDWARE, - ) - })) + .then(|| { + config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(database_path); + sc_sysinfo::gather_hwbench( + Some(database_path), + &SUBSTRATE_REFERENCE_HARDWARE, + ) + }) + }) .flatten(); let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) diff --git a/templates/parachain/node/src/main.rs b/templates/parachain/node/src/main.rs index 12738a6793c0..46ebcfd266d9 100644 --- a/templates/parachain/node/src/main.rs +++ b/templates/parachain/node/src/main.rs @@ -2,6 +2,8 @@ #![warn(missing_docs)] +use polkadot_sdk::*; + mod chain_spec; mod cli; mod command; diff --git a/templates/parachain/node/src/rpc.rs b/templates/parachain/node/src/rpc.rs index 4937469e11e2..7549a5d090d7 100644 --- a/templates/parachain/node/src/rpc.rs +++ b/templates/parachain/node/src/rpc.rs @@ -9,6 +9,8 @@ use std::sync::Arc; use parachain_template_runtime::{opaque::Block, AccountId, Balance, Nonce}; +use polkadot_sdk::*; + use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 04e20be2bd40..8c526317283e 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -3,14 +3,16 @@ // std use std::{sync::Arc, time::Duration}; -use cumulus_client_cli::CollatorOptions; // Local Runtime Types use parachain_template_runtime::{ apis::RuntimeApi, opaque::{Block, Hash}, }; +use polkadot_sdk::*; + // Cumulus Imports +use cumulus_client_cli::CollatorOptions; use cumulus_client_collator::service::CollatorService; #[docify::export(lookahead_collator)] use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; @@ -55,7 +57,7 @@ pub type Service = PartialComponents< ParachainBackend, (), sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, (ParachainBlockImport, Option, Option), >; @@ -105,12 +107,15 @@ pub fn new_partial(config: &Configuration) -> Result telemetry }); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); @@ -171,7 +176,7 @@ fn start_consensus( telemetry: Option, task_manager: &TaskManager, relay_chain_interface: Arc, - transaction_pool: Arc>, + transaction_pool: Arc>, keystore: KeystorePtr, relay_chain_slot_duration: Duration, para_id: ParaId, @@ -265,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, @@ -282,9 +287,7 @@ pub async fn start_parachain_node( if parachain_config.offchain_worker.enabled { use futures::FutureExt; - task_manager.spawn_handle().spawn( - "offchain-workers-runner", - "offchain-work", + let offchain_workers = sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { runtime_api_provider: client.clone(), keystore: Some(params.keystore_container.keystore()), @@ -296,9 +299,11 @@ pub async fn start_parachain_node( is_validator: parachain_config.role.is_authority(), enable_http_requests: false, custom_extensions: move |_| vec![], - }) - .run(client.clone(), task_manager.spawn_handle()) - .boxed(), + })?; + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-work", + offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(), ); } @@ -401,7 +406,5 @@ pub async fn start_parachain_node( )?; } - start_network.start_network(); - Ok((task_manager, client)) } diff --git a/templates/parachain/pallets/template/Cargo.toml b/templates/parachain/pallets/template/Cargo.toml index dde863101372..dc1088cb33fe 100644 --- a/templates/parachain/pallets/template/Cargo.toml +++ b/templates/parachain/pallets/template/Cargo.toml @@ -13,45 +13,16 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { features = [ - "derive", -], workspace = true } -scale-info = { features = [ - "derive", -], workspace = true } +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } -# frame deps -frame-benchmarking = { optional = true, workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } - -# primitive deps -sp-runtime = { workspace = true } - -[dev-dependencies] -sp-core = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } +frame = { workspace = true, default-features = false, features = [ + "experimental", + "runtime", +] } [features] default = ["std"] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -std = [ - "codec/std", - "scale-info/std", - - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - - "sp-runtime/std", -] -try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "sp-runtime/try-runtime", -] +runtime-benchmarks = ["frame/runtime-benchmarks"] +std = ["codec/std", "frame/std", "scale-info/std"] +try-runtime = ["frame/try-runtime"] diff --git a/templates/parachain/pallets/template/src/benchmarking.rs b/templates/parachain/pallets/template/src/benchmarking.rs index 29572c3ff609..9f2d09904f50 100644 --- a/templates/parachain/pallets/template/src/benchmarking.rs +++ b/templates/parachain/pallets/template/src/benchmarking.rs @@ -1,7 +1,7 @@ //! Benchmarking setup for pallet-template use super::*; -use frame_benchmarking::v2::*; +use frame::{deps::frame_benchmarking::v2::*, prelude::*}; #[benchmarks] mod benchmarks { diff --git a/templates/parachain/pallets/template/src/lib.rs b/templates/parachain/pallets/template/src/lib.rs index 6bfb98972aed..211bef51aa86 100644 --- a/templates/parachain/pallets/template/src/lib.rs +++ b/templates/parachain/pallets/template/src/lib.rs @@ -66,17 +66,13 @@ mod benchmarking; // To see a full list of `pallet` macros and their use cases, see: // // -#[frame_support::pallet] +#[frame::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*, DefaultNoBound}; - use frame_system::pallet_prelude::*; - use sp_runtime::traits::{CheckedAdd, One}; + use frame::prelude::*; /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] pub trait Config: frame_system::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - /// type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A type representing the weights required by the dispatchables of this pallet. diff --git a/templates/parachain/pallets/template/src/mock.rs b/templates/parachain/pallets/template/src/mock.rs index b8c730b6eb5d..b924428d4145 100644 --- a/templates/parachain/pallets/template/src/mock.rs +++ b/templates/parachain/pallets/template/src/mock.rs @@ -1,9 +1,12 @@ -use frame_support::{derive_impl, weights::constants::RocksDbWeight}; -use frame_system::{mocking::MockBlock, GenesisConfig}; -use sp_runtime::{traits::ConstU64, BuildStorage}; +use frame::{ + deps::{frame_support::weights::constants::RocksDbWeight, frame_system::GenesisConfig}, + prelude::*, + runtime::prelude::*, + testing_prelude::*, +}; // Configure a mock runtime to test the pallet. -#[frame_support::runtime] +#[frame_construct_runtime] mod test_runtime { #[runtime::runtime] #[runtime::derive( @@ -39,6 +42,6 @@ impl crate::Config for Test { } // Build genesis storage according to the mock runtime. -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestState { GenesisConfig::::default().build_storage().unwrap().into() } diff --git a/templates/parachain/pallets/template/src/tests.rs b/templates/parachain/pallets/template/src/tests.rs index 2f641ce08fbb..14609fd6dba7 100644 --- a/templates/parachain/pallets/template/src/tests.rs +++ b/templates/parachain/pallets/template/src/tests.rs @@ -1,5 +1,5 @@ use crate::{mock::*, Error, Something}; -use frame_support::{assert_noop, assert_ok}; +use frame::testing_prelude::*; #[test] fn it_works_for_default_value() { diff --git a/templates/parachain/pallets/template/src/weights.rs b/templates/parachain/pallets/template/src/weights.rs index 4b4522429c6c..9295492bc20b 100644 --- a/templates/parachain/pallets/template/src/weights.rs +++ b/templates/parachain/pallets/template/src/weights.rs @@ -29,7 +29,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame::{deps::frame_support::weights::constants::RocksDbWeight, prelude::*}; use core::marker::PhantomData; /// Weight functions needed for pallet_template. diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 236b7c048632..f1d33b4143e4 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -17,14 +17,10 @@ substrate-wasm-builder = { optional = true, workspace = true, default-features = docify = { workspace = true } [dependencies] -codec = { features = [ - "derive", -], workspace = true } +codec = { features = ["derive"], workspace = true } hex-literal = { optional = true, workspace = true, default-features = true } log = { workspace = true } -scale-info = { features = [ - "derive", -], 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"] } @@ -32,168 +28,66 @@ serde_json = { workspace = true, default-features = false, features = ["alloc"] # Local pallet-parachain-template = { workspace = true } -# Substrate / FRAME -frame-benchmarking = { optional = true, workspace = true } -frame-executive = { workspace = true } -frame-metadata-hash-extension = { workspace = true } -frame-support = { features = ["experimental"], 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 } +polkadot-sdk = { workspace = true, default-features = false, features = [ + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-message-queue", + "pallet-session", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", -# FRAME Pallets -pallet-aura = { workspace = true } -pallet-authorship = { workspace = true } -pallet-balances = { workspace = true } -pallet-message-queue = { 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-xcm", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", -# Substrate Primitives -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-transaction-pool = { workspace = true } -sp-version = { workspace = true } + "cumulus-pallet-aura-ext", + "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", + "pallet-collator-selection", + "parachains-common", + "staging-parachain-info", -# 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 } + "runtime", +] } # Cumulus -cumulus-pallet-aura-ext = { 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 } -pallet-collator-selection = { workspace = true } -parachains-common = { workspace = true } -parachain-info = { workspace = true } [features] default = ["std"] std = [ "codec/std", - "cumulus-pallet-aura-ext/std", "cumulus-pallet-parachain-system/std", - "cumulus-pallet-session-benchmarking/std", - "cumulus-pallet-xcm/std", - "cumulus-pallet-xcmp-queue/std", - "cumulus-primitives-aura/std", - "cumulus-primitives-core/std", - "cumulus-primitives-storage-weight-reclaim/std", - "cumulus-primitives-utility/std", - "frame-benchmarking?/std", - "frame-executive/std", - "frame-metadata-hash-extension/std", - "frame-support/std", - "frame-system-benchmarking?/std", - "frame-system-rpc-runtime-api/std", - "frame-system/std", - "frame-try-runtime?/std", "log/std", - "pallet-aura/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-collator-selection/std", - "pallet-message-queue/std", "pallet-parachain-template/std", - "pallet-session/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "pallet-transaction-payment-rpc-runtime-api/std", - "pallet-transaction-payment/std", - "pallet-xcm/std", - "parachain-info/std", - "parachains-common/std", - "polkadot-parachain-primitives/std", - "polkadot-runtime-common/std", + "polkadot-sdk/std", "scale-info/std", "serde_json/std", - "sp-api/std", - "sp-block-builder/std", - "sp-consensus-aura/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-transaction-pool/std", - "sp-version/std", "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", ] runtime-benchmarks = [ "cumulus-pallet-parachain-system/runtime-benchmarks", - "cumulus-pallet-session-benchmarking/runtime-benchmarks", - "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "cumulus-primitives-utility/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system-benchmarking/runtime-benchmarks", - "frame-system/runtime-benchmarks", "hex-literal", - "pallet-balances/runtime-benchmarks", - "pallet-collator-selection/runtime-benchmarks", - "pallet-message-queue/runtime-benchmarks", "pallet-parachain-template/runtime-benchmarks", - "pallet-sudo/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "pallet-xcm/runtime-benchmarks", - "parachains-common/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", - "polkadot-runtime-common/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", - "xcm-executor/runtime-benchmarks", + "polkadot-sdk/runtime-benchmarks", ] try-runtime = [ - "cumulus-pallet-aura-ext/try-runtime", "cumulus-pallet-parachain-system/try-runtime", - "cumulus-pallet-xcm/try-runtime", - "cumulus-pallet-xcmp-queue/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-aura/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-collator-selection/try-runtime", - "pallet-message-queue/try-runtime", "pallet-parachain-template/try-runtime", - "pallet-session/try-runtime", - "pallet-sudo/try-runtime", - "pallet-timestamp/try-runtime", - "pallet-transaction-payment/try-runtime", - "pallet-xcm/try-runtime", - "parachain-info/try-runtime", - "polkadot-runtime-common/try-runtime", - "sp-runtime/try-runtime", + "polkadot-sdk/try-runtime", ] # Enable the metadata hash generation. diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs index 243db1b6dde0..05a508ca655f 100644 --- a/templates/parachain/runtime/src/apis.rs +++ b/templates/parachain/runtime/src/apis.rs @@ -25,6 +25,9 @@ // External crates imports use alloc::vec::Vec; + +use polkadot_sdk::*; + use frame_support::{ genesis_builder_helper::{build_state, get_preset}, weights::Weight, @@ -241,10 +244,10 @@ impl_runtime_apis! { impl frame_benchmarking::Benchmark for Runtime { fn benchmark_metadata(extra: bool) -> ( Vec, - Vec, + Vec, ) { use frame_benchmarking::{Benchmarking, BenchmarkList}; - use frame_support::traits::StorageInfoTrait; + use polkadot_sdk::frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use super::*; @@ -258,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::*; @@ -277,7 +280,7 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_benchmarking::Config for Runtime {} - use frame_support::traits::WhitelistedStorageKeys; + use polkadot_sdk::frame_support::traits::WhitelistedStorageKeys; let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); let mut batches = Vec::::new(); diff --git a/templates/parachain/runtime/src/benchmarks.rs b/templates/parachain/runtime/src/benchmarks.rs index 9fbf1ad82bdb..aae50e7258c0 100644 --- a/templates/parachain/runtime/src/benchmarks.rs +++ b/templates/parachain/runtime/src/benchmarks.rs @@ -23,7 +23,7 @@ // // For more information, please refer to -frame_benchmarking::define_benchmarks!( +polkadot_sdk::frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] [pallet_balances, Balances] [pallet_session, SessionBench::] diff --git a/templates/parachain/runtime/src/configs/mod.rs b/templates/parachain/runtime/src/configs/mod.rs index 43ab63bd0b67..ba4c71c7f218 100644 --- a/templates/parachain/runtime/src/configs/mod.rs +++ b/templates/parachain/runtime/src/configs/mod.rs @@ -25,6 +25,10 @@ mod xcm_config; +use polkadot_sdk::{staging_parachain_info as parachain_info, staging_xcm as xcm, *}; +#[cfg(not(feature = "runtime-benchmarks"))] +use polkadot_sdk::{staging_xcm_builder as xcm_builder, staging_xcm_executor as xcm_executor}; + // Substrate and Polkadot dependencies use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; @@ -173,6 +177,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = (); } impl pallet_sudo::Config for Runtime { diff --git a/templates/parachain/runtime/src/configs/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs index e162bcbf8868..3da3b711f4ff 100644 --- a/templates/parachain/runtime/src/configs/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -2,6 +2,11 @@ use crate::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; + +use polkadot_sdk::{ + staging_xcm as xcm, staging_xcm_builder as xcm_builder, staging_xcm_executor as xcm_executor, *, +}; + use frame_support::{ parameter_types, traits::{ConstU32, Contains, Everything, Nothing}, diff --git a/templates/parachain/runtime/src/genesis_config_presets.rs b/templates/parachain/runtime/src/genesis_config_presets.rs index fec53d17394c..aa1ff7895eb8 100644 --- a/templates/parachain/runtime/src/genesis_config_presets.rs +++ b/templates/parachain/runtime/src/genesis_config_presets.rs @@ -1,17 +1,23 @@ -use cumulus_primitives_core::ParaId; - use crate::{ AccountId, BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, PolkadotXcmConfig, RuntimeGenesisConfig, SessionConfig, SessionKeys, SudoConfig, EXISTENTIAL_DEPOSIT, }; + use alloc::{vec, vec::Vec}; -use parachains_common::{genesis_config_helpers::*, AuraId}; + +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_core::sr25519; use sp_genesis_builder::PresetId; +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; /// Generate the session keys from individual elements. /// @@ -26,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() @@ -34,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 @@ -51,48 +56,22 @@ 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 { testnet_genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], - get_account_id_from_seed::("Alice"), - 1000.into(), + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + Sr25519Keyring::Alice.to_account_id(), + PARACHAIN_ID.into(), ) } @@ -100,39 +79,20 @@ fn development_config_genesis() -> Value { testnet_genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], - get_account_id_from_seed::("Alice"), - 1000.into(), + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + Sr25519Keyring::Alice.to_account_id(), + PARACHAIN_ID.into(), ) } /// 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 ccec648ce4c1..43e76dba0591 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -16,8 +16,11 @@ mod weights; extern crate alloc; use alloc::vec::Vec; 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,9 +36,6 @@ use frame_support::weights::{ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; - use weights::ExtrinsicBaseWeight; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. @@ -72,9 +72,9 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. +/// The extension to the basic transaction logic. #[docify::export(template_signed_extra)] -pub type SignedExtra = ( +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -89,7 +89,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// All migrations of the runtime, aside from the ones declared in the pallets. /// @@ -140,13 +140,12 @@ impl WeightToFeePolynomial for WeightToFee { /// to even the core data structures. pub mod opaque { use super::*; - use sp_runtime::{ + pub use polkadot_sdk::sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + use polkadot_sdk::sp_runtime::{ generic, traits::{BlakeTwo256, Hash as HashT}, }; - pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - /// Opaque block header type. pub type Header = generic::Header; /// Opaque block type. @@ -165,8 +164,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/parachain/runtime/src/weights/block_weights.rs b/templates/parachain/runtime/src/weights/block_weights.rs index e7fdb2aae2a0..9e095a412ec2 100644 --- a/templates/parachain/runtime/src/weights/block_weights.rs +++ b/templates/parachain/runtime/src/weights/block_weights.rs @@ -16,6 +16,8 @@ // limitations under the License. pub mod constants { + use polkadot_sdk::*; + use frame_support::{ parameter_types, weights::{constants, Weight}, @@ -29,6 +31,8 @@ pub mod constants { #[cfg(test)] mod test_weights { + use polkadot_sdk::*; + use frame_support::weights::constants; /// Checks that the weight exists and is sane. diff --git a/templates/parachain/runtime/src/weights/extrinsic_weights.rs b/templates/parachain/runtime/src/weights/extrinsic_weights.rs index 1a4adb968bb7..1a00a9cd0398 100644 --- a/templates/parachain/runtime/src/weights/extrinsic_weights.rs +++ b/templates/parachain/runtime/src/weights/extrinsic_weights.rs @@ -16,6 +16,8 @@ // limitations under the License. pub mod constants { + use polkadot_sdk::*; + use frame_support::{ parameter_types, weights::{constants, Weight}, @@ -29,6 +31,8 @@ pub mod constants { #[cfg(test)] mod test_weights { + use polkadot_sdk::*; + use frame_support::weights::constants; /// Checks that the weight exists and is sane. diff --git a/templates/parachain/runtime/src/weights/paritydb_weights.rs b/templates/parachain/runtime/src/weights/paritydb_weights.rs index 25679703831a..9071c58ec7f2 100644 --- a/templates/parachain/runtime/src/weights/paritydb_weights.rs +++ b/templates/parachain/runtime/src/weights/paritydb_weights.rs @@ -16,6 +16,8 @@ // limitations under the License. pub mod constants { + use polkadot_sdk::*; + use frame_support::{ parameter_types, weights::{constants, RuntimeDbWeight}, @@ -32,6 +34,8 @@ pub mod constants { #[cfg(test)] mod test_db_weights { + use polkadot_sdk::*; + use super::constants::ParityDbWeight as W; use frame_support::weights::constants; diff --git a/templates/parachain/runtime/src/weights/rocksdb_weights.rs b/templates/parachain/runtime/src/weights/rocksdb_weights.rs index 3dd817aa6f13..89e0b643aabe 100644 --- a/templates/parachain/runtime/src/weights/rocksdb_weights.rs +++ b/templates/parachain/runtime/src/weights/rocksdb_weights.rs @@ -16,6 +16,8 @@ // limitations under the License. pub mod constants { + use polkadot_sdk::*; + use frame_support::{ parameter_types, weights::{constants, RuntimeDbWeight}, @@ -32,6 +34,8 @@ pub mod constants { #[cfg(test)] mod test_db_weights { + use polkadot_sdk::*; + use super::constants::RocksDbWeight as W; use frame_support::weights::constants; diff --git a/templates/parachain/zombienet-omni-node.toml b/templates/parachain/zombienet-omni-node.toml new file mode 100644 index 000000000000..29e99cfcd493 --- /dev/null +++ b/templates/parachain/zombienet-omni-node.toml @@ -0,0 +1,22 @@ +[relaychain] +default_command = "polkadot" +chain = "rococo-local" + +[[relaychain.nodes]] +name = "alice" +validator = true +ws_port = 9944 + +[[relaychain.nodes]] +name = "bob" +validator = true +ws_port = 9955 + +[[parachains]] +id = 1000 +chain_spec_path = "" + +[parachains.collator] +name = "charlie" +ws_port = 9988 +command = "polkadot-omni-node" diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index a0285e048d1b..4c0ab31df95e 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -30,9 +30,9 @@ 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 = { 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-genesis-builder = { workspace = true, default-features = true } @@ -72,6 +72,7 @@ std = ["solochain-template-runtime/std"] runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "sc-service/runtime-benchmarks", "solochain-template-runtime/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/templates/solochain/node/src/benchmarking.rs b/templates/solochain/node/src/benchmarking.rs index 1bd3578af689..0d60230cd19c 100644 --- a/templates/solochain/node/src/benchmarking.rs +++ b/templates/solochain/node/src/benchmarking.rs @@ -109,7 +109,7 @@ pub fn create_benchmark_extrinsic( .checked_next_power_of_two() .map(|c| c / 2) .unwrap_or(2) as u64; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -126,7 +126,7 @@ pub fn create_benchmark_extrinsic( let raw_payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -145,7 +145,7 @@ pub fn create_benchmark_extrinsic( call, sp_runtime::AccountId32::from(sender.public()).into(), runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) } diff --git a/templates/solochain/node/src/command.rs b/templates/solochain/node/src/command.rs index e2c7657c95cc..1c23e395ede9 100644 --- a/templates/solochain/node/src/command.rs +++ b/templates/solochain/node/src/command.rs @@ -144,11 +144,12 @@ pub fn run() -> sc_cli::Result<()> { let ext_builder = RemarkBuilder::new(client.clone()); cmd.run( - config, + config.chain_spec.name().into(), client, inherent_benchmark_data()?, Vec::new(), &ext_builder, + false, ) }, BenchmarkCmd::Extrinsic(cmd) => { diff --git a/templates/solochain/node/src/service.rs b/templates/solochain/node/src/service.rs index 2de543235ec8..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}; @@ -31,7 +28,7 @@ pub type Service = sc_service::PartialComponents< FullBackend, FullSelectChain, sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ( sc_consensus_grandpa::GrandpaBlockImport, sc_consensus_grandpa::LinkHalf, @@ -67,12 +64,15 @@ pub fn new_partial(config: &Configuration) -> Result { let select_chain = sc_consensus::LongestChain::new(backend.clone()); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( @@ -169,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, @@ -188,15 +178,13 @@ 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, })?; if config.offchain_worker.enabled { - task_manager.spawn_handle().spawn( - "offchain-workers-runner", - "offchain-worker", + let offchain_workers = sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions { runtime_api_provider: client.clone(), is_validator: config.role.is_authority(), @@ -208,9 +196,11 @@ pub fn new_full< network_provider: Arc::new(network.clone()), enable_http_requests: true, custom_extensions: |_| vec![], - }) - .run(client.clone(), task_manager.spawn_handle()) - .boxed(), + })?; + task_manager.spawn_handle().spawn( + "offchain-workers-runner", + "offchain-worker", + offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(), ); } @@ -339,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 8a7fa74a5977..837849e844b1 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -81,18 +81,14 @@ substrate-wasm-builder = { optional = true, workspace = true, default-features = default = ["std"] std = [ "codec/std", - "scale-info/std", - + "frame-benchmarking?/std", "frame-executive/std", "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", - - "frame-benchmarking?/std", "frame-try-runtime?/std", - "pallet-aura/std", "pallet-balances/std", "pallet-grandpa/std", @@ -101,7 +97,8 @@ std = [ "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", - + "scale-info/std", + "serde_json/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -109,15 +106,13 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", - - "serde_json/std", - "sp-keyring/std", "substrate-wasm-builder", ] @@ -131,6 +126,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-template/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] diff --git a/templates/solochain/runtime/src/apis.rs b/templates/solochain/runtime/src/apis.rs index 87a09a5f7fee..06c645fa0c53 100644 --- a/templates/solochain/runtime/src/apis.rs +++ b/templates/solochain/runtime/src/apis.rs @@ -223,6 +223,7 @@ impl_runtime_apis! { use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use super::*; @@ -236,10 +237,11 @@ 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; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use super::*; diff --git a/templates/solochain/runtime/src/benchmarks.rs b/templates/solochain/runtime/src/benchmarks.rs index f39c2bd29593..59012e0b047e 100644 --- a/templates/solochain/runtime/src/benchmarks.rs +++ b/templates/solochain/runtime/src/benchmarks.rs @@ -26,6 +26,7 @@ frame_benchmarking::define_benchmarks!( [frame_benchmarking, BaselineBench::] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_timestamp, Timestamp] [pallet_sudo, Sudo] diff --git a/templates/solochain/runtime/src/configs/mod.rs b/templates/solochain/runtime/src/configs/mod.rs index 4f77ad37fe64..e34b3cb82158 100644 --- a/templates/solochain/runtime/src/configs/mod.rs +++ b/templates/solochain/runtime/src/configs/mod.rs @@ -133,7 +133,7 @@ impl pallet_balances::Config for Runtime { type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = VariantCountOf; type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; type DoneSlashHandler = (); } @@ -148,6 +148,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; type FeeMultiplierUpdate = ConstFeeMultiplier; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_sudo::Config for Runtime { diff --git a/templates/solochain/runtime/src/genesis_config_presets.rs b/templates/solochain/runtime/src/genesis_config_presets.rs index 693ae5c2221f..049f4593451b 100644 --- a/templates/solochain/runtime/src/genesis_config_presets.rs +++ b/templates/solochain/runtime/src/genesis_config_presets.rs @@ -17,6 +17,7 @@ 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; @@ -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. @@ -91,9 +88,9 @@ pub fn local_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::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 bc47f3aeac85..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`, @@ -146,8 +146,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The `TransactionExtension` to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -161,10 +161,10 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// All migrations of the runtime, aside from the ones declared in the pallets. /// diff --git a/templates/zombienet/tests/smoke.rs b/templates/zombienet/tests/smoke.rs index ba5f42142f31..c0c9646d4e9c 100644 --- a/templates/zombienet/tests/smoke.rs +++ b/templates/zombienet/tests/smoke.rs @@ -7,28 +7,74 @@ //! `cargo build --package minimal-template-node --release` //! `export PATH=/target/release:$PATH //! -//! The you can run the test with -//! `cargo test -p template-zombienet-tests` +//! There are also some tests related to omni node which run basaed on pre-generated chain specs, +//! so to be able to run them you would need to generate the right chain spec (just minimal and +//! parachain tests supported for now). +//! +//! You can run the following command to generate a minimal chainspec, once the runtime wasm file is +//! compiled: +//!`chain-spec-builder create --relay-chain --para-id 1000 -r \ +//! named-preset development` +//! +//! Once the files are generated, you must export an environment variable called +//! `CHAIN_SPECS_DIR` which should point to the absolute path of the directory +//! that holds the generated chain specs. The chain specs file names should be +//! `minimal_chain_spec.json` for minimal and `parachain_chain_spec.json` for parachain +//! templates. +//! +//! To start all tests here we should run: +//! `cargo test -p template-zombienet-tests --features zombienet` #[cfg(feature = "zombienet")] mod smoke { + use std::path::PathBuf; + use anyhow::anyhow; use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder, NetworkConfigExt}; - pub fn get_config(cmd: &str, para_cmd: Option<&str>) -> Result { - let chain = if cmd == "polkadot" { "rococo-local" } else { "dev" }; + const CHAIN_SPECS_DIR_PATH: &str = "CHAIN_SPECS_DIR"; + const PARACHAIN_ID: u32 = 1000; + + #[inline] + fn expect_env_var(var_name: &str) -> String { + std::env::var(var_name) + .unwrap_or_else(|_| panic!("{CHAIN_SPECS_DIR_PATH} environment variable is set. qed.")) + } + + #[derive(Default)] + struct NetworkSpec { + relaychain_cmd: &'static str, + relaychain_spec_path: Option, + // TODO: update the type to something like Option> after + // `zombienet-sdk` exposes `shared::types::Arg`. + relaychain_cmd_args: Option>, + para_cmd: Option<&'static str>, + para_cmd_args: Option>, + } + + fn get_config(network_spec: NetworkSpec) -> Result { + let chain = if network_spec.relaychain_cmd == "polkadot" { "rococo-local" } else { "dev" }; let config = NetworkConfigBuilder::new().with_relaychain(|r| { - r.with_chain(chain) - .with_default_command(cmd) - .with_node(|node| node.with_name("alice")) + let mut r = r.with_chain(chain).with_default_command(network_spec.relaychain_cmd); + if let Some(path) = network_spec.relaychain_spec_path { + r = r.with_chain_spec_path(path); + } + + if let Some(args) = network_spec.relaychain_cmd_args { + r = r.with_default_args(args.into_iter().map(|arg| arg.into()).collect()); + } + + r.with_node(|node| node.with_name("alice")) .with_node(|node| node.with_name("bob")) }); - let config = if let Some(para_cmd) = para_cmd { + let config = if let Some(para_cmd) = network_spec.para_cmd { config.with_parachain(|p| { - p.with_id(1000) - .with_default_command(para_cmd) - .with_collator(|n| n.with_name("collator")) + let mut p = p.with_id(PARACHAIN_ID).with_default_command(para_cmd); + if let Some(args) = network_spec.para_cmd_args { + p = p.with_default_args(args.into_iter().map(|arg| arg.into()).collect()); + } + p.with_collator(|n| n.with_name("collator")) }) } else { config @@ -46,14 +92,18 @@ mod smoke { env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), ); - let config = get_config("polkadot", Some("parachain-template-node"))?; + let config = get_config(NetworkSpec { + relaychain_cmd: "polkadot", + para_cmd: Some("parachain-template-node"), + ..Default::default() + })?; let network = config.spawn_native().await?; // wait 6 blocks of the para let collator = network.get_node("collator")?; assert!(collator - .wait_metric("block_height{status=\"best\"}", |b| b > 5_f64) + .wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64) .await .is_ok()); @@ -66,13 +116,19 @@ mod smoke { env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), ); - let config = get_config("solochain-template-node", None)?; + let config = get_config(NetworkSpec { + relaychain_cmd: "solochain-template-node", + ..Default::default() + })?; let network = config.spawn_native().await?; // wait 6 blocks let alice = network.get_node("alice")?; - assert!(alice.wait_metric("block_height{status=\"best\"}", |b| b > 5_f64).await.is_ok()); + assert!(alice + .wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64) + .await + .is_ok()); Ok(()) } @@ -83,13 +139,73 @@ mod smoke { env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), ); - let config = get_config("minimal-template-node", None)?; + let config = get_config(NetworkSpec { + relaychain_cmd: "minimal-template-node", + ..Default::default() + })?; + + let network = config.spawn_native().await?; + + // wait 6 blocks + let alice = network.get_node("alice")?; + assert!(alice + .wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64) + .await + .is_ok()); + + Ok(()) + } + + #[tokio::test(flavor = "multi_thread")] + async fn omni_node_with_minimal_runtime_block_production_test() -> Result<(), anyhow::Error> { + let _ = env_logger::try_init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + let chain_spec_path = expect_env_var(CHAIN_SPECS_DIR_PATH) + "/minimal_chain_spec.json"; + let config = get_config(NetworkSpec { + relaychain_cmd: "polkadot-omni-node", + relaychain_cmd_args: Some(vec![("--dev-block-time", "1000")]), + relaychain_spec_path: Some(chain_spec_path.into()), + ..Default::default() + })?; let network = config.spawn_native().await?; // wait 6 blocks let alice = network.get_node("alice")?; - assert!(alice.wait_metric("block_height{status=\"best\"}", |b| b > 5_f64).await.is_ok()); + assert!(alice + .wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64) + .await + .is_ok()); + + Ok(()) + } + + #[tokio::test(flavor = "multi_thread")] + async fn omni_node_with_parachain_runtime_block_production_test() -> Result<(), anyhow::Error> { + let _ = env_logger::try_init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + + let chain_spec_path = expect_env_var(CHAIN_SPECS_DIR_PATH) + "/parachain_chain_spec.json"; + + let config = get_config(NetworkSpec { + relaychain_cmd: "polkadot", + para_cmd: Some("polkadot-omni-node"), + // Leaking the `String` to be able to use it below as a static str, + // required by the `FromStr` implementation for zombienet-configuration + // `Arg` type, which is not exposed yet through `zombienet-sdk`. + para_cmd_args: Some(vec![("--chain", chain_spec_path.leak())]), + ..Default::default() + })?; + let network = config.spawn_native().await?; + + // wait 6 blocks + let alice = network.get_node("collator")?; + assert!(alice + .wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64) + .await + .is_ok()); Ok(()) } diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 3e7edc739821..7f50658c4e16 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -148,6 +148,7 @@ std = [ "pallet-tx-pause?/std", "pallet-uniques?/std", "pallet-utility?/std", + "pallet-verify-signature?/std", "pallet-vesting?/std", "pallet-whitelist?/std", "pallet-xcm-benchmarks?/std", @@ -251,6 +252,7 @@ runtime-benchmarks = [ "frame-system?/runtime-benchmarks", "pallet-alliance?/runtime-benchmarks", "pallet-asset-conversion-ops?/runtime-benchmarks", + "pallet-asset-conversion-tx-payment?/runtime-benchmarks", "pallet-asset-conversion?/runtime-benchmarks", "pallet-asset-rate?/runtime-benchmarks", "pallet-asset-tx-payment?/runtime-benchmarks", @@ -321,11 +323,13 @@ runtime-benchmarks = [ "pallet-sudo?/runtime-benchmarks", "pallet-timestamp?/runtime-benchmarks", "pallet-tips?/runtime-benchmarks", + "pallet-transaction-payment?/runtime-benchmarks", "pallet-transaction-storage?/runtime-benchmarks", "pallet-treasury?/runtime-benchmarks", "pallet-tx-pause?/runtime-benchmarks", "pallet-uniques?/runtime-benchmarks", "pallet-utility?/runtime-benchmarks", + "pallet-verify-signature?/runtime-benchmarks", "pallet-vesting?/runtime-benchmarks", "pallet-whitelist?/runtime-benchmarks", "pallet-xcm-benchmarks?/runtime-benchmarks", @@ -335,7 +339,7 @@ runtime-benchmarks = [ "parachains-common?/runtime-benchmarks", "polkadot-cli?/runtime-benchmarks", "polkadot-node-metrics?/runtime-benchmarks", - "polkadot-parachain-lib?/runtime-benchmarks", + "polkadot-omni-node-lib?/runtime-benchmarks", "polkadot-parachain-primitives?/runtime-benchmarks", "polkadot-primitives?/runtime-benchmarks", "polkadot-runtime-common?/runtime-benchmarks", @@ -438,6 +442,7 @@ try-runtime = [ "pallet-recovery?/try-runtime", "pallet-referenda?/try-runtime", "pallet-remark?/try-runtime", + "pallet-revive-mock-network?/try-runtime", "pallet-revive?/try-runtime", "pallet-root-offences?/try-runtime", "pallet-root-testing?/try-runtime", @@ -460,13 +465,14 @@ try-runtime = [ "pallet-tx-pause?/try-runtime", "pallet-uniques?/try-runtime", "pallet-utility?/try-runtime", + "pallet-verify-signature?/try-runtime", "pallet-vesting?/try-runtime", "pallet-whitelist?/try-runtime", "pallet-xcm-bridge-hub-router?/try-runtime", "pallet-xcm-bridge-hub?/try-runtime", "pallet-xcm?/try-runtime", "polkadot-cli?/try-runtime", - "polkadot-parachain-lib?/try-runtime", + "polkadot-omni-node-lib?/try-runtime", "polkadot-runtime-common?/try-runtime", "polkadot-runtime-parachains?/try-runtime", "polkadot-sdk-frame?/try-runtime", @@ -492,7 +498,6 @@ serde = [ "pallet-parameters?/serde", "pallet-referenda?/serde", "pallet-remark?/serde", - "pallet-revive?/serde", "pallet-state-trie-migration?/serde", "pallet-tips?/serde", "pallet-transaction-payment?/serde", @@ -536,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-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-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 = [ "frame-benchmarking", "frame-benchmarking-pallet-pov", @@ -600,16 +605,11 @@ runtime = [ "sp-wasm-interface", "sp-weights", ] -node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-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-overseer", "polkadot-parachain-lib", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] +node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-revive-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"] tuples-96 = [ "frame-support-procedural?/tuples-96", "frame-support?/tuples-96", ] -riscv = [ - "pallet-revive-fixtures?/riscv", - "pallet-revive-mock-network?/riscv", - "pallet-revive?/riscv", -] [package.edition] workspace = true @@ -1332,6 +1332,11 @@ path = "../substrate/frame/utility" default-features = false optional = true +[dependencies.pallet-verify-signature] +path = "../substrate/frame/verify-signature" +default-features = false +optional = true + [dependencies.pallet-vesting] path = "../substrate/frame/vesting" default-features = false @@ -1892,6 +1897,11 @@ path = "../substrate/frame/contracts/mock-network" default-features = false optional = true +[dependencies.pallet-revive-eth-rpc] +path = "../substrate/frame/revive/rpc" +default-features = false +optional = true + [dependencies.pallet-revive-mock-network] path = "../substrate/frame/revive/mock-network" default-features = false @@ -2082,13 +2092,13 @@ path = "../polkadot/node/subsystem-util" default-features = false optional = true -[dependencies.polkadot-overseer] -path = "../polkadot/node/overseer" +[dependencies.polkadot-omni-node-lib] +path = "../cumulus/polkadot-omni-node/lib" default-features = false optional = true -[dependencies.polkadot-parachain-lib] -path = "../cumulus/polkadot-parachain/polkadot-parachain-lib" +[dependencies.polkadot-overseer] +path = "../polkadot/node/overseer" default-features = false optional = true diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 656273029fe8..2216864fad0f 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -580,6 +580,10 @@ pub use pallet_remark; #[cfg(feature = "pallet-revive")] pub use pallet_revive; +/// An Ethereum JSON-RPC server for 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; @@ -705,6 +709,10 @@ pub use pallet_uniques; #[cfg(feature = "pallet-utility")] pub use pallet_utility; +/// FRAME verify signature pallet. +#[cfg(feature = "pallet-verify-signature")] +pub use pallet_verify_signature; + /// FRAME pallet for manage vesting. #[cfg(feature = "pallet-vesting")] pub use pallet_vesting; @@ -898,14 +906,14 @@ pub use polkadot_node_subsystem_types; #[cfg(feature = "polkadot-node-subsystem-util")] pub use polkadot_node_subsystem_util; +/// Helper library that can be used to build a parachain node. +#[cfg(feature = "polkadot-omni-node-lib")] +pub use polkadot_omni_node_lib; + /// System overseer of the Polkadot node. #[cfg(feature = "polkadot-overseer")] pub use polkadot_overseer; -/// Helper library that can be used to build a parachain node. -#[cfg(feature = "polkadot-parachain-lib")] -pub use polkadot_parachain_lib; - /// Types and utilities for creating and working with parachains. #[cfg(feature = "polkadot-parachain-primitives")] pub use polkadot_parachain_primitives;